数组、list、map都需要遍历循环,有下面集中循环方式
1.for ecah
list可以是一个数组、list、set
// list可以是一个数组、list、set
for(bject o :list)
{
}
2.Iterator迭代器
list可以是list、set类的子类
Iterator iter = list.iterator();
while(iter.hasNext()){
Object o = iter.next();
}
3.loop with size
可以是数组、list能得到索引长度的类及子类
for(int i=0;i<list.size();i++){
Object o= list.get(i);
}
4.lambda表达式
list.forEach(
(value)->{
System.out.println(value);
}
);
代码示例
public class GanHuo {
@Test
public void t1(){
//1.for-each遍历,最简单,但无法获得索引
System.out.println("=======for(Object:list)循环=========");
String arrayStr[]=new String[]{"1","2","3"};
//1-1 数组
System.out.println("for-each遍历数组-----------");
for (String s : arrayStr) {
System.out.println("arrayStr:"+s);
}
//1-2 list
List<Integer> list= Arrays.asList(1,2,3,4);
System.out.println("for-each遍历list-----------");
for (Integer i : list) {
System.out.println("list:"+i);
}
//1-3 遍历map
Map<String,String> map=new HashMap<>();
System.out.println("for-each遍历Map-----------");
map.put("1", "111");
map.put("2", "222");
map.put("3", "222");
//得到key的collecton
Set<String> keySet=map.keySet();
for(String key:keySet){
System.out.println("map["+key+"]="+map.get(key));
}
}
@Test
public void t2(){
System.out.println("=======Iterator循环================");
//1-2 list
List<Integer> list= Arrays.asList(1,2,3,4);
System.out.println("Iterator 遍历list-----------");
Iterator iter=list.iterator();
while (iter.hasNext()) {
System.out.println("list:"+iter.next());
}
//1-3 遍历map
Map<String,String> map=new HashMap<>();
System.out.println("Iterator 遍历Map-----------");
map.put("1", "111");
map.put("2", "222");
map.put("3", "222");
//得到key的collecton
Set<String> keySet=map.keySet();
iter=keySet.iterator();
while (iter.hasNext()) {
String key= (String) iter.next();
System.out.println("map["+key+"]="+map.get(key));
}
}
@Test
public void t3(){
System.out.println("=======for。size循环================");
//1-1 数组
String arrayStr[]=new String[]{"1","2","3"};
System.out.println("loop size 遍历数组-----------");
for (int i = 0; i < arrayStr.length; i++) {
System.out.println("arrayStr["+i+"]="+arrayStr[i]);
}
//1-2 list
List<Integer> list= Arrays.asList(1,2,3,4);
System.out.println("loop size 遍历list-----------");
for (int i = 0; i < list.size(); i++) {
System.out.println("list["+i+"]="+list.get(i));
}
}
@Test
public void t4(){
System.out.println("=======lambda表达式================");
//list的lambda表达式
List<Integer> list= Arrays.asList(1,2,3,4);
System.out.println("lambda表达式 遍历list-----------");
list.forEach(
(value)->{
System.out.println(value);
}
);
//Map的lambda表达式
Map<String,String> map=new HashMap<>();
System.out.println("lambda表达式 遍历Map-----------");
map.put("1", "111");
map.put("2", "222");
map.put("3", "222");
map.forEach((key, value)->{
System.out.print("key = " + key);
System.out.println(", value = " + value);
});
}
}
可变参数是指不指定参数的个数
定义:
数据类型… 变量名
可变参数规范
1.可变参数本身是一个数组
2.可变参数也可传递一个数组
3.可变参数个数不受限制,可无限制,也可没有
4.如果可变参数和常规参数混合,则可变参数要放到最后
5.每个方法最多只能有一个可变参数
代码示例
public class ChangeParam {
public void param(Integer... val){
System.out.println("val包含:"+val.length+"个参数");
for (Integer i : val) {
System.out.println(i);
}
}
/***
如果一个方法里包含常规参数和可变参数,则可变参数必须放置到最后一个
*/
public void param1(String name,Integer age,String... likes){
System.out.println("name:"+name);
System.out.println("age:"+age);
System.out.println("likes-----");
String temp="";
for (String like : likes) {
temp+=like+",";
}
System.out.println(temp);
}
@Test
public void t1(){
//可以传递不受限制的个数
param(1,2,3);
//可以不传参数
param();
//也可传递数组
Integer[] array={1,2,3};
param(array);
//常规和可变参数混合
param1("蒋增奎",20,"火锅","串串","烤鸭");
}
}
1.使用List=Arrays.asList(数组对象),最简单,但不能新增删除
2.List=new ArrayList<>(Arrays.asList(intArray)),可新增删除,但性能差
3. Collections.addAll(list对象, 数组对象);可新增删除,性能好
4.list= Stream.of(数组对象).collect(Collectors.toList());
@Test
public void array2List(){
System.out.println("=========Arrays.asList=======");
//1---直接用Arrays.asList后不能再新增
System.out.println("1---直接用Arrays.asList后不能再新增");
//基本类型数组
Integer[] intArray={1,2,3};
List<Object> list1= Arrays.asList(intArray);
// list1.add(4); //不能再新增,否则要报异常
printList(list1);
//自定义数组
TestVO[] objArray={new TestVO(1,"jzk"),new TestVO(2,"张三")};
list1=Arrays.asList(objArray);
printList(list1);
//2--Arrays.asList作为构造参数传入,可新增,但性能差
System.out.println("2--Arrays.asList作为构造参数传入,可新增,但性能差");
list1=new ArrayList<>(Arrays.asList(intArray));
list1.add(4);
printList(list1);
//3--Collections.addAll(list,数组);能新增删除,性能好
System.out.println("3--Collections.addAll(list,数组);能新增删除,性能好");
list1=new ArrayList<>();
Collections.addAll(list1, intArray);
list1.add(4);
printList(list1);
//4--使用 Stream;能新增删除,性能好
System.out.println("4--使用 Stream;能新增删除,性能好");
list1= Stream.of(intArray).collect(Collectors.toList());
list1.add(4);
printList(list1);
}
private void printList(List<Object> list){
for (Object o : list) {
System.out.println(o);
}
}
核心用到list.toArray()方法
1.Object[] arrays=list.toArray(); 只能获得Object数组
2.对象数组=list.toArray(new 对象[list.size] ) ;//可以获得对应的对象数组
测试代码
@Test
public void list2array(){
List<TestVO> list=getTestVO();
System.out.println("方法1:list.toArray()===========");
//注意:只能用转换成Object[]数组,不能强制转化
Object[] arrays=list.toArray();
for (Object array : arrays) {
System.out.println((TestVO)array);
}
System.out.println("方法2:list.toArray(数组对象)===========");
//这样可获得实际的类
TestVO[] vos=new TestVO[list.size()];
list.toArray(vos );
for (TestVO vo : vos) {
System.out.println(vo);
}
//或者这样写
System.out.println("方法3:list.toArray(数组对象)简写===========");
vos=list.toArray(new TestVO[list.size()]);
for (TestVO vo : vos) {
System.out.println(vo);
}
System.out.println("方法4:String[] strings = list.stream().toArray(String[]::new);===");
TestVO[] vos2=list.stream().toArray( TestVO[]::new);
for (TestVO vo : vos2) {
System.out.println(vo);
}
}
private void printList(List<Object> list){
for (Object o : list) {
System.out.println(o);
}
}
private List<TestVO> getTestVO(){
List<TestVO> list=new ArrayList<>();
list.add(new TestVO(1,"jzk"));
list.add(new TestVO(2,"张三"));
return list;
}
在学习 Java 编程语言的过程中,我们经常会听到“值传递”和“地址传递”这两个概念。它们是用来描述参数传递方式的术语,而理解它们的区别对于编写高效的代码非常重要。在本文中,我们将详细介绍这两种传递方式,并通过代码示例来说明它们的差异。
在 Java 中,基本数据类型(如整数、布尔值等)都是以值传递的方式进行参数传递。这意味着当我们将一个基本数据类型作为参数传递给一个方法时,方法内部会创建一个新的变量来存储这个参数的值,而不会影响原始的变量。
执行过程
基本数据类型的传递过程中,传入的值被复制到方法内部,并在方法内部进行操作,但不会影响原始变量的值。
@Test
public void valPass(){
String str="a";
double db= Double.parseDouble("34.5");
Double db1=45.2;
Integer zs=Integer.valueOf(100);
int zs1=200;
boolean b=false;
Boolean b1= true;
System.out.println("str="+str);
System.out.println("db="+db);
System.out.println("db1="+db1);
System.out.println("zs="+zs);
System.out.println("zs1="+zs1);
System.out.println("b="+b);
System.out.println("b1="+b1);
change1(str,db,db1,zs,zs1);
System.out.println("str="+str);
System.out.println("db="+db);
System.out.println("db1="+db1);
System.out.println("zs="+zs);
System.out.println("zs1="+zs1);
}
private void change1(String str,double db,Double db1,int zs,Integer zs1){
System.out.println("============change==========");
str="b";
db=-45.2;
db1=-22.4;
zs=-1;
zs1=-2;
}
执行效果,可以看出这些都是值传递,被引用后并没有改变以前值:
str=a
db=34.5
db1=45.2
zs=100
zs1=200
b=false
b1=true
============change==========
str=a
db=34.5
db1=45.2
zs=100
zs1=200
与基本数据类型不同,Java 中的对象类型(如数组、集合、自定义类等)则是以地址传递的方式进行参数传递。这意味着当我们将一个对象作为参数传递给一个方法时,方法内部使用的是这个对象的引用,而不是对象本身。
执行过程
创建一个对象并将其引用赋值给一个变量。
将这个变量作为参数传递给一个方法。
在方法内部,参数变量接收到了对原始对象的引用。
在方法内部修改参数变量所指向的对象时,原始对象也会受到影响。
方法执行完毕后,返回到原始调用处,可以通过原始变量访问到被修改后的对象。
对象的引用传递意味着传递的是对象的引用,通过引用可以访问和修改原始对象的属性。
测试代码:
@Test
public void addressPass(){
StringBuffer sb=new StringBuffer("aa");
TestVO vo=new TestVO(1,"蒋增奎");
String[] array={"1","2","3"};
List<Integer> list=new ArrayList<>();
list.add(1);list.add(2);
Map<String,Integer> map=new HashMap<>();
map.put("1", 11);
map.put("2", 22);
System.out.println("sb:"+sb);
System.out.println("vo:"+vo);
System.out.println("array:"+ Arrays.toString(array));
System.out.println("list:"+Arrays.toString(list.toArray()));
System.out.println("map:"+map.toString());
System.out.println("================");
change2(sb,vo,array,list,map);
System.out.println("sb:"+sb);
System.out.println("vo:"+vo);
System.out.println("array:"+ Arrays.toString(array));
System.out.println("list:"+Arrays.toString(list.toArray()));
System.out.println("map:"+map.toString());
}
private void change2( StringBuffer sb, TestVO vo,String[] array,
List<Integer> list,Map<String,Integer> map){
sb.append("dd");
vo.setName("蒋大爷");
array[0]="改值11";
list.add(3);
map.put("3",333);
}
效果,地址引用值都会被改变
sb:aa
vo:TestVO(id=1, name=蒋增奎)
array:[1, 2, 3]
list:[1, 2]
map:{1=11, 2=22}
================
sb:aadd
vo:TestVO(id=1, name=蒋大爷)
array:[改值11, 2, 3]
list:[1, 2, 3]
map:{1=11, 2=22, 3=333}
代码2:
@Test
public void t2() {
TestVO vo1=new TestVO(1, "jzk");
TestVO vo2=vo1;
vo2.setName("奎哥");
System.out.println(vo1); //打印TestVO(id=1, name=奎哥),不是jzk
System.out.println(vo2);//TestVO(id=1, name=奎哥)
}
首先创建一个对象TestVO vo1,接着申请另一款空间,用来创建TestVO vo2,且vo2=vo1,说明两个数组都指向同一块空间,修改vo2中的字段也就相当于修改了vo1中对应的元素。
代码3
@Test
public void t1(){
TestVO vo=new TestVO(1, "jzk");
System.out.println(vo);
change3(vo);
System.out.println(vo);
change4(vo);
System.out.println(vo);
}
private void change3(TestVO vo){
TestVO vo1=vo; //把vo赋值给vo1,两个对象是指向同一个地址
vo1.setName("奎哥");
}
private void change4(TestVO vo){
vo.setName("鸡哥");
}
打印效果:
TestVO(id=1, name=jzk)
TestVO(id=1, name=奎哥)
TestVO(id=1, name=鸡哥)
代码说明:
change3()和change4()效果一样,change3()虽然通过了赋值,但两个对象指向的同一个地址
易错点
java对象:String ,int等对应的封装类Integer,java.util.Date,BigDecimal是值传递,不是地址传递,虽然他们是对象
值传递VS地址传递
Java基本类型共有八种,基本类型可以分为三类,字符类型char,布尔类型boolean以及数值类型byte、short、int、long、float、double。数值类型又可以分为整数类型byte、short、int、long和浮点数类型float、double。JAVA中的数值类型不存在无符号的,它们的取值范围是固定的,不会随着机器硬件环境或者操作系统的改变而改变。实际上,JAVA中还存在另外一种基本类型void,它也有对应的包装类 java.lang.Void,不过我们无法直接对它们进行操作
代码说明
//基础数据类型
@Test
public void t1(){
//1.整数类型
byte b=100;
short s=10000;
int i=1000000000;
//注意:长整型long要加L后缀,才能最大化
long l=900000000000000000L;
System.out.println("byte:"+b);
System.out.println("short:"+s);
System.out.println("int:"+i);
System.out.println("long:"+l);
//2.浮点型
//注意:小数默认是double,如果要用float,需要再数字后面加f或者F
float f=34.67f;
double d=34.67;
//char类型,char必须用单引号包围,只能一个字符
char c1='A';
char c2='2';
//boolean
boolean b1=false;
}
注意事项:
1.整数:short int long 就是取值范围不一样,对计算没有影响,当然计算性能存储越低性能越高,long后面需要增加L/l后缀
2.浮点型:小数默认为double类型,float要加l/L后缀,double计算精度高,但性能差些,但高精度计算用BigDecmal(小数存在计算精度问题)
3.基础类型不能赋null,只有对应包装类才行
默认值和初始化
每一种类型都有一个默认值,除基本类型外,其他的类型的默认值都是 null,因为它们都是引用类型。整数默认为 int 类型,浮点数默认为 double 类型。
代码
public float f;
public double d;
public boolean b;
private int i;
private Boolean b3;
@Test
public void t2(){
//静态方法有默认值
System.out.println(f); //0
System.out.println(d); //0
System.out.println(i); //0
System.out.println(b); //false
System.out.println(b3); //null
boolean b1;
System.out.println(b1); //编译不通过
}
注意事项:
1.只有为class的字段属性声明才有默认值
2.在方法内声明的变量,如果不赋初始值,编译不通过
Java 是面向对象的语言,但是为了便于开发者的使用,Java 中却沿用了 C 语言的基本数据类型,在进行基本的数据计算时,开发者可以直接使用基础类。但是基本数据类型是不具备对象的特征的,不能调用方法,而且基本数据类型不能存入集合中,所以就需要将基础数据类型实例封装为 Java 对象,使其具有了对象的属性和方法。
基础类型和包装类的区别
存储位置不同:
基本数据类型直接将值放在栈中;
包装类型是把对象放在堆中,然后通过对象的引用来调用他们 ;
初始值不同:
int的初始值为 0 、 boolean的初始值为false ;
包装类型的初始值为null ;
使用方式不同:
基本数据类型直接赋值使用就好;
在集合如 coolectionMap 中只能使用包装类型;
在应用场景中MVC模式的form-vo,Dto,PO对象的属性最好都用包装类,因为基础类型都有默认值0或者false,在实际应用中,null和0,false是有实际意义的
包装类是java对象,封装有相关方法,而基础类型没有
比如:Integer.valueOf()等
为什么还要保留基础类型?
基础类型之间的转换
(1)基础类型自动转化
1.范围小的类型可以自动转换成范围大的类型。
2.整型可以自动转换成浮点型
3.反之,范围大的转化为范围小的必须强制转换
4.范围:short->int->long->float->double ,从小到大
示例代码:
@Test
public void t3(){
System.out.println("1.自动转换===========");
byte i1=2;
short i2=i1;
int i3=i2;
long i4=i3;
float f1=3.45f;
double f2=f1;
float f3=i3;
double f4=i4;
}
(2)强制执行
范围大的转化为范围小的,必须用强制转换
范围大的类型需要强制转换成范围小的类型,否则会精度丢失。
强制类型转换可能会导致数据溢出或者产生负数。
范围小到范围大的的转换也可以用强制转化,和自动转换效果一样
@Test
public void t4(){
System.out.println("2.强制转换===========");
double f1=34.56565;
float f2=(float) f1;
int i=(int)f1;
System.out.println(i);
//范围小的转换也可以用强制转化,和自动转换效果一样
int i1=34;
float f3=(float)i1;
}
基本类型和包装类的转换
基本类型与包装类之间的转换需要使用到自动装箱和拆箱的操作。
@Test
public void t5(){
System.out.println("3.基本类型和封装类转换===========");
int i=10;
Integer i1=i; //自动装箱
Integer i2=30;
int i3=i2;//自动拆箱
}
包装类的常用方法
1.包装类对象=包装类.valueOf(对应的基础类型);
2.基础数据类型/包装类对象=包装类.parseXXX(字符串) ;字符串转化成数据类型
@Test
public void t6() {
System.out.println("4.包装类的常用方法===========");
Integer i = Integer.valueOf(2);
int i1 = Integer.parseInt("344"); //字符串转成整数
Integer i2 = Integer.parseInt("34444"); //实际是转化成int,int在装箱成Integer
System.out.println(i);
System.out.println(i1);
System.out.println(i2);
}
1.char和String的区别
char是字符类型,是基础数据类型,长度固定,用单引号表示 如 c=‘谢’;
String是字符串类型,不是基础数据类型,长度无法确定,用双引号表示 str=“傻啊”。
关于String类。
(1)、String类时final类,所以是不可继承的;
( 2)、String类是的本质是字符数组char[];
( 3)、Java运行时会维护一个String Pool(String池),JavaDoc翻译很模糊“字符串缓冲区”。String池用来存放运行时中产 生的各种字符串,并且池中的字符串的内容不重复。而一般对象不存在这个缓冲池,并且创建的对象仅仅存在于方法的堆 栈区。
4.String虽然是对象,但传参也是值传递,不是地址传递
@Test
public void t7() {
String s="abc";
Character c='中';
char[] cs= s.toCharArray();
for (char c1 : cs) {
System.out.println(c1);
}
char[] cs2={'天','地','人'};
String s1=new String(cs2);
System.out.println(s1);
}
字符串有两种创建方式,String s1=“a”; String s=new String(“a”)其逻辑是不一样的
1.直接创建 String str1 = “123”
直接创建的 String 类的数据存储在公共的常量池中(Java 的常量优化机制),即直接创建的相同值的不同 String 类的引用相同。
2.new 创建 String str1 =new String(“123”)
通过 new 关键字创建的 String 和其他一般的类的创建一样,数据是存储在 String 类的对象的堆上,即通过 new 关键字创建的相同值的不同 String 类的引用不同。
String str1 = "Java";
String str2 = "Java";
String str3 = str2 + "";
String str4=new String("Java");
String str5=new String("Java");
String str6=str1;
String str7=str4
System.out.println(str1 == str2); // Output: true
System.out.println(str2 == str3); // Output: false
System.out.println(str4== str5); // Output: false
System.out.println(str1== str5); // Output: false
System.out.println(str1== str6); // Output: true
System.out.println(str4== str7); // Output: true
代码说明:
(str1 == str2)== true
直接创建String,其实就是放到常量池里的对象,直接创建时,先去常量池寻找,如果有,则引用,所以这两个时一个东西
(str2 == str3)==false
str3 = str2 + “”;代码实际上是创建了一个StringBuild对象,已经是两个对象了
(str4 == str4)==false
两个字符串都是new String(“Java”),是两个对象,所以为false
1.字符串String
字符串类是final修饰,不可继承和修改的,
String s="a";
s=s+"b";
其实是产生了两个字符串,执行s=s+“b”;后,s="a"就被丢弃在公共常量池里,如果进行大量的修改,
会导致性能很差。
2.字符串StringBuffer
在 Java1.0 的时候,若要对字符串进行大量修改,应当使用 StringBuffer,它是可修改的,同时,当时的开发人员考虑到多个线程对一个字符串的修改可能出现线程不安全的问题,于是让 StringBuffer 在拥有可修改字符串的功能的情况下,又给它加上了线程安全的机制。看到这里是不是觉得还挺好,挺正常的?但是要知道一个前提,那就是在 Java5 之前的 Java 在处理字符串的速度上一直被别人诟病,原因出在哪里?原因就在于这个 StringBuffer 上面。
StringBuffer 本来是为了实现大量修改字符串的功能而出现的,但却因为 Java 的开发人员给它加了个线程安全的功能,导致它执行效率极大地下降。这个线程安全的功能的实现并不是像我们现在用的方法,当时只是保证没有异常抛出,程序可以正常运行下去而已。在 Java 中,要实现字符串的相加,用加法运算符将两个字符串相加即可。但在这个过程中,Java5 之前是有 String 自动隐含地转换成 StringBuffer,再进行操作这一个步骤的(毕竟 String 类不可直接修改)。只要有这些步骤,就可以实现字符串的修改,但是呢,StringBuffer 有个线程安全的功能,它会在上面提到的步骤中还额外的执行一些功能,以保证线程的安全,而且,这里实现线程安全的方式和我们现在用锁的方式是不一样的!它这里的实现线程安全的方式极为繁琐且复杂,这就大大降低了 StringBuffer 的执行效率,以至于后来被广大程序员诟病。
3.字符串StringBuilder
我们仔细地想一下,实际上也并没有多少地方需要在修改字符串的同时保证线程安全,就算有,我们给它加个锁就行。基于这种想法,在 StringBuffer 出现 10 年之后,Java 的开发人员回过头看这个问题,才发现 StringBuffer 的实现是多么的愚蠢,于是后来在 Java5 就有了 StringBuilder。StringBuilder 同样可以快速高效地修改字符串,同时不是线程安全的。虽然它不是线程安全的,但是它的执行效率却比 StringBuffer 要高上了不少。在 Java5 之后的版本中,字符串相加隐含的转化过程中,不再将 String 转化为 StringBuffer,而是转化成 StringBuilder。
总结:
在大量操作字符串时,java已经优化了,不推荐使用StringBuffer
数组有多种定义方式
@Test
public void t1() {
//第一种定义数组的方法:
int[] array1 = {1, 2, 3};//直接赋值(静态初始化)
//int[]是数组的类型,array为数组名,随意取名字
//第二种定义数组的方法:
int[] array2 = new int[]{1, 2, 3, 4};//数组的动态初始化
//第三种定义数组的方法:
int[] array3 = new int[10];//只是分配了内存,但是没有进行赋值,默认值都是0,
System.out.println(array3[2]); //0
//第四种定义数组的方法:
int[] array4;
array4 = new int[]{1, 2, 3};//一定要为数组符初值,不然编译器会报错,
int[] array5=null;//等价int[] array4
}
4.注意事项
地址引用:
int[] array1 = {1,2,3,4};
System.out.print(Arrays.toString(array1));//打印[1,2,3,4]
int[] array2 = array1;
array2[1] = 99;
System.out.print(Arrays.toString(array1));//打印[1,99,3,4],不是[1,2,3,4]
System.out.print(Arrays.toString(array2));//打印[1,99,3,4]
首先创建一个数组array1,并初始化赋值为1,2,3,4,然后打印数组array1,接着申请另一款空间,用来创建array2,且array2=array1,说明两个数组都指向同一块空间,修改array2中的第二个元素也就相当于修改了array1中对应的元素。
Arrays提供了几个很有用的数组帮助方法:
方法 | 说明 |
---|---|
toString | 把数组转化为字符串 |
sort | 数组元素排序 |
binarySearch | 查找元素在数组中的位置索引 |
asList | 把数组转化成list |
直接看代码,一目了然
@Test
public void t3(){
System.out.println("Arrays类的常见用法");
int[] array={5,4,2,6,3};
//1.打印
String str=Arrays.toString(array);
System.out.println(str);//[5, 4, 2, 6, 3]
//2.数组大小排序
Arrays.sort(array);
System.out.println(Arrays.toString(array));//[2, 3, 4, 5, 6]
//3.判断两个数组内容是否相等
int[] array1={1,2,3};
int[] array2={1,2,3};
System.out.println(Arrays.equals(array1, array2)); //true
System.out.println(array1.equals(array2));//false,不能采用这个方法判断数组内容
//3.查找某个元素的索引
int[] array3={1,2,3};
int index=Arrays.binarySearch(array3,2);
System.out.println(index); //1
//注意事项,如果没有,则返回小于0,如果多个,则返回第一个
int[] array4={1,2,3,2};
System.out.println(Arrays.binarySearch(array4, 2));//1
System.out.println("ddd:"+Arrays.binarySearch(array4, 4));//小于零
//4.转化成list数据类型
Integer[] array5={1,2,3};
//如果是对象,则直接List<对应的数组元素类型>
List<Integer> list=Arrays.asList(array5);
for (Integer i : list) {
System.out.println(i);
}
// list.add(9); //运行报错,不能新增和删除
// list.remove(0);//运行报错,不能新增和删除
/***
注意如果数组是基本数据类型,用Array.asList是无法转化的。
需要借助第三方先把基本类型数组转化成对应的包装类数组
如:Apache Commons Lang3
*/
int[] array6={1,2,3,5};
Integer[] array7= ArrayUtils.toObject(array6);
//4.copy值
int[] arr1 = {1, 2, 3};
int[] arr2 = Arrays.copyOf(arr1, 5);
System.out.println(Arrays.toString(arr2)); //[1, 2, 3, 0, 0]
//注意:copyOf是值copy,不是地址引用
arr2[3]=20;
System.out.println(Arrays.toString(arr2));//[1, 2, 3, 20, 0]
System.out.println(Arrays.toString(arr1));//[1, 2, 3]
//copyOfRange方法提供了开始索引
int[] arr3 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int[] arr4 = new int[5];
arr4 = Arrays.copyOfRange(arr3,3,5);
System.out.println(Arrays.toString(arr4));//[4, 5]
}
org.apache.commons.lang3.ArrayUtils这个类也很大扩展了数组的操作,具体查看apache文档
“== ”在哪些情况下比较的是对象内容而不是引用
代码1
@Test
public void t1(){
//基本类型数据(数值、字符、布尔)的值一样,则==为true
char c1='a';
char c2='a';
float f1=3.5f;
float f2=3.5f;
double f3=3.5;
int i1=1;
int i2=1;
long i3=1l;
System.out.println(c1==c2);//true
System.out.println(f1==f2);//true
System.out.println(f1==f3);//true
System.out.println(i1==i2);//true
System.out.println(i1==i3);//true
}
代码2: 字符串是一个对象又有基础数据的特殊性,可参考2.6.2
@Test
public void t2(){
String s1="123";
String s2="123";
String s3=s1;
String s4=s2+"";
String s5=new String("123");
String s6=new String("123");
String s7=s5;
//s="xx"是直接声明,String是final常量,性质和基础数据类型一样,s1,s2都指向同一个内存地址
System.out.println(s1==s2); //true
//所有=变量赋值的语法,指针都是一样
System.out.println(s1==s3); //true
//因为String是final类型,s2+""实际是创建一个对象
System.out.println(s1==s4); //false
//两个不同对象,内存地址不一样
System.out.println(s5==s6); //false
//所有=变量赋值的语法,指针都是一样
System.out.println(s5==s7); //true
//如果是euqal比较,这几个都返回true
System.out.println( //true
s1.equals(s2) && s1.equals(s3) && s1.equals(s4) && s5.equals(s6)
);
}
}
代码3:标准vo对象
@Test
public void t3(){
TestVO vo1=new TestVO(1,"jzk");
TestVO vo2=vo1;
TestVO vo3=new TestVO(1,"jzk");
//内存指针一样
System.out.println(vo1==vo2);//true
//两个不同对象
System.out.println(vo1==vo3);//false
//三个对象值都是一样的
System.out.println(vo1.equals(vo2) && vo2.equals(vo3));//true
//vo2修改了值,因为vo1指针和他一致,所以vo1也会改变,最后他们都是一致的
vo2.setName("奎哥");
System.out.println(vo1==vo2);//true
//值已经改变了
System.out.println(vo3.equals(vo1));//false
}
equals 和 hashCode 之间有什么关系?
equals 和 hashCode 在Java中通常一起使用,以维护对象在散列集合(如HashMap和HashSet)中的正确行为。
如果两个对象相等(根据equals方法的定义),那么它们的hashCode值应该相同。
也就是说,如果重写了一个类的equals方法,通常也需要重写hashCode方法,以便它们保持一致。
这是因为散列集合使用对象的hashCode值来确定它们在内部存储结构中的位置。
obj.compareTo(object otherstr);
仅仅知道两个字符串是否相同是不够的。对于排序应用来说,必须知道一个字符串是大于、等于还是小于另一个。一个字符串小于另一个指的是它在字典中先出现。而一个字符串大于另一个指的是它在字典中后出现。字符串(String)的 compareTo() 方法实现了这种功能。
代码:
@Test
public void t4(){
//字符串比较
String s1="a";
String s2="abc";
System.out.println(s1.compareTo(s2));
//基本类型的包装类比较
Integer i1=3;
Integer i2=5;
System.out.println(i1.compareTo(i2));//<0
System.out.println(i1<i2);//true
//日期Date,BigDecimal
Date d1= DateUtil.getDateByStr("2003-10-01", DateUtil.date_gs);
Date d2= DateUtil.getDateByStr("2004-09-01", DateUtil.date_gs);
System.out.println(d1.compareTo(d2));//<0
BigDecimal bg1=new BigDecimal("1.0");
BigDecimal bg2=new BigDecimal("1.00");
System.out.println(bg1.equals(bg2)); //返回的是false,所以比较BigDecimal不要用equals
System.out.println(bg1.compareTo(bg2));//0
}
}