目录
面向对象
多态性
向下转型
Object
equals()
toString()
clone()
finalize()
Static
单例模式
代码块
final
抽象类与抽象方法(或abstract关键字)
接口
接口的多态性
接口的默认方法
内部类
成员内部类
局部内部类
枚举类
实现接口的枚举类
注解(Annotation)
包装类
相互转换:
包装类的其它API
包装类对象的特点
包装类对象不可变
面向对象
多态性
多态性,是面向对象中最重要的概念,在Java中的体现:对象的多态性:父类的引用指向子类的对象
父类类型 变量名 = 子类对象;
例如
Father f = new Son();
上面这种情况,当Son类重写了方法时,f会调用Son的方法
在编译时,f被认为是Father类,在运行时被认为是Son类:编译时,看左边;运行时,看右边。
多态的使用前提:① 类的继承关系 ② 方法的重写
属性不具备多态性,调f的属性一定是来自于Father,且无法访问 到Son类的属性
f也无法调用Son类特有的方法(弊端)
使用场景
现在我定义了三个类:人,男人,女人,之间存在继承关系
class person{public void eat(){System.out.println("人吃饭");}
}class man extends person {public void eat(){System.out.println("男人吃饭");}public void work(){System.out.println("男人工作");}
}class woman extends person {public void eat(){System.out.println("女人吃饭");}
}
在另外一个类中我声明了一个方法,我希望能调用不同类的eat方法:
public class test {public static void main(String[] args){test tt = new test();tt.eating(new man());//男人吃饭}public void eating(person p){p.eat();}
}
上面这种情况,方法在声明的时候,形参写的是person类,但是传入的是man类,调用的也是man类的方法,这就用到了多态
如果没有多态,就得定义三个重载eating函数了
向下转型
类似于强制类型转换,在编译中一直认为f是Father类,那么只需要将f强制转换为man类就可以调用man类中独有的方法和属性
public static void main(String[] args){test tt = new test();person p = new man();man m = (man)p;m.work();}
此处m和p的地址是一样的,其实相当于内存中已经加载了man和person的内容,只是在调用的时候有一些限制,现在强制转换之后可以就行调用了,用的是同一块地址
但是下面这种就不可以,因为内存中没有加载man的方法和属性
public static void main(String[] args){test tt = new test();person p = new woman();man m = (man)p;m.work();}
instanceof判断实例属于的类,在向下转型的时候可以先判断一下
person p = new man();System.out.println(p instanceof person);//trueSystem.out.println(p instanceof man);//trueSystem.out.println(p instanceof woman);//true
Object
类 java.lang.Object
是类层次结构的根类,即所有其它类的父类。每个类都使用 Object
作为超类。
Object类型的变量与除Object以外的任意引用数据类型的对象都存在多态引用
method(Object obj){…} //可以接收任何类作为其参数Person o = new Person();
method(o);
Object方法:
equals()
在object类中,这个方法的作用是比较两个对象的地址是否一样
public static void main(String[] args) throws InterruptedException {man p1 = new man();man p2 = new man();System.out.println(p1.equals(p2));//false}
但是在某些引用数据类型上,这个方法可能被重写了,例如在String类中,它被重写为判断两个字符串内容是不是一样,类似的还有File、Date类
public static void main(String[] args) throws InterruptedException {String s1 = "abcdefg";String s2 = "abcdefg";int[] a1 = {1,2,3,4};int[] a2 = {1,2,3,4};System.out.println(s1.equals(s2));//trueSystem.out.println(a1.equals(a2));//false}
这个和 == 的区别就是:
== 既可以比较基本类型也可以比较引用类型。对于基本类型就是比较值,对于引用类型就是比较内存地址
equals的话,它是属于java.lang.Object类里面的方法,如果该方法没有被重写过默认也是==;String等类的equals方法是被重写过的,而且String类在日常开发中用的比较多,久而久之,形成了equals是比较值的错误观点。
具体要看自定义类里有没有重写Object的equals方法来判断。
通常情况下,重写equals方法,会比较类中的相应属性是否都相等
==如果两端数据类型不一样会报错
toString()
① 默认情况下,toString()返回的是“对象的运行时类型 @ 对象的hashCode值的十六进制形式"
② 在进行String与其它类型数据的连接操作时,自动调用toString()方法
③ 如果我们直接System.out.println(对象),默认会自动调用这个对象的toString()
④ 可以根据需要在用户自定义类型中重写toString()方法
如String 类重写了toString()方法,返回字符串的值。
clone()
对象的克隆,使用时有一些要求:
1、实现Cloneable接口
2、重写clone方法
3、在使用时必须使用try catch捕获异常
public class test {public static void main(String[] args){test tt = new test();man p = new man();p.name=33;try {man p2 = (man)(p.clone());System.out.println(p2.name);//33System.out.println(p2 == p);//false} catch (CloneNotSupportedException e) {e.printStackTrace();}}
}class man implements Cloneable{int age = 1;int name = 22;protected Object clone() throws CloneNotSupportedException {// TODO Auto-generated method stubreturn super.clone();}
}
注意:Object中的clone方法是浅拷贝
finalize()
- 当对象被回收时,系统自动调用该对象的 finalize() 方法。(不是垃圾回收器调用的,是本类对象调用的)
- 永远不要主动调用某个对象的finalize方法,应该交给垃圾回收机制调用。
- 什么时候被回收:当某个对象没有任何引用时,JVM就认为这个对象是垃圾对象,就会在之后不确定的时间使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用 finalize()方法。
- 子类可以重写该方法,目的是在对象被清理之前执行必要的清理操作。比如,在方法内断开相关连接资源。
- 如果重写该方法,让一个新的引用变量重新引用该对象,则会重新激活对象。
- 在JDK 9中此方法已经被
标记为过时
的。
也需要在类中重写方法
public class test {public static void main(String[] args) throws InterruptedException {test tt = new test();man p = new man();p = null;System.gc(); //释放空间}
}class man implements Cloneable{protected void finalize() throws Throwable{System.out.println("对象被释放");}
}
Static
如果想让一个成员变量被类的所有实例所共享,就用static修饰即可,称为类变量(或类属性、静态变量)
静态变量:
public class test {public static void main(String[] args) throws InterruptedException {man m = new man();man m2 = new man();System.out.println(m.country);//cnSystem.out.println(m2.country);//cnm.country = "China";System.out.println(m.country);//ChinaSystem.out.println(m2.country);//China}
}
class man {static String country = "cn";
}
静态变量的默认值规则和实例变量一样。
静态变量值是所有对象共享。
静态变量在本类中,可以在任意方法、代码块、构造器中直接使用。
如果权限修饰符允许,在其他类中可以通过“
类名.静态变量
”直接访问,也可以通过“对象.静态变量
”的方式访问(但是更推荐使用类名.静态变量的方式)。静态变量的get/set方法也静态的,当局部变量与静态变量
重名时
,使用“类名.静态变量
”进行区分。在jdk6之前,静态变量放在方法区,jdk7之后放在堆空间
静态方法
- 静态方法在本类的任意方法、代码块、构造器中都可以直接被调用。
- 只要权限修饰符允许,静态方法在其他类中可以通过“类名.静态方法“的方式调用。也可以通过”对象.静态方法“的方式调用(但是更推荐使用类名.静态方法的方式)。
- 在static方法内部只能访问类的static修饰的属性或方法,不能访问类的非static的结构。
- 静态方法可以被子类继承,但不能被子类重写。
- 静态方法的调用都只看编译时类型。
- 因为不需要实例就可以访问static方法,因此static方法内部不能有this,也不能有super。如果有重名问题,使用“类名.”进行区别。
单例模式
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。
如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将
类的构造器的访问权限设置为private
,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法
以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的
。
第一种方式:饿汉式
public class test {public static void main(String[] args) throws InterruptedException {Singleton S1 = Singleton.getInstance();Singleton S2 = Singleton.getInstance();System.out.println(S1 == S2); // true}
}class Singleton{private Singleton(){}private static Singleton instance = new Singleton();public static Singleton getInstance(){return instance;}
}
第二种方式:懒汉式
public class test {public static void main(String[] args) throws InterruptedException {Singleton S1 = Singleton.getInstance();Singleton S2 = Singleton.getInstance();System.out.println(S1 == S2); // true}
}class Singleton{private Singleton(){}private static Singleton instance = null;public static Singleton getInstance(){if(instance == null){instance = new Singleton();return instance;}else{return instance;}}
}
饿汉式:
- 特点:
立即加载
,即在使用类的时候已经将对象创建完毕。- 优点:实现起来
简单
;没有多线程安全问题。- 缺点:当类被加载的时候,会初始化static的实例,静态变量被创建并分配内存空间,从这以后,这个static的实例便一直占着这块内存,直到类被卸载时,静态变量被摧毁,并释放所占有的内存。因此在某些特定条件下会
耗费内存
。懒汉式:
- 特点:
延迟加载
,即在调用静态方法时实例才被创建。- 优点:实现起来比较简单;当类被加载的时候,static的实例未被创建并分配内存空间,当静态方法第一次被调用时,初始化实例变量,并分配内存,因此在某些特定条件下会
节约内存
。- 缺点:在多线程环境中,这种实现方法是完全错误的,
线程不安全
,根本不能保证单例的唯一性。
代码块
1、代码块是在类中直接以 {} 包含的一段代码,主要功能是进行初始化
2、其修饰前缀只能是 static ,故可以分为静态代码块和非静态代码块
3、静态代码块随着 类 加载而执行,所以只会执行一次,而非静态代码块随着 对象 加载和执行,可以执行多次
public class test {public static void main(String[] args) throws InterruptedException {System.out.println(Singleton.age);//静态代码块 3System.out.println(Singleton.age);//3Singleton S1 = new Singleton();//非静态代码块Singleton S2 = new Singleton();//非静态代码块}
}class Singleton{public static int age = 3;{System.out.println("非静态代码块");}static {System.out.println("静态代码块");}
}
4、静态代码块不能调用非静态的属性和方法,非静态代码块可以
5、执行顺序是:静态代码块>非静态代码块>构造方法
public class test {public static void main(String[] args) throws InterruptedException {Singleton S1 = new Singleton();//3333 2222 1111}
}class Singleton{public Singleton(){System.out.println("1111");}{System.out.println("2222");}static {System.out.println("3333");}
}
6、代码块可以写多个,同类代码块之间的执行顺序按照声明的顺序
final
final:最终的,不可更改的
final修饰类
表示这个类不能被继承,没有子类。提高安全性,提高程序的可读性。
final class Eunuch{//太监类
}
class Son extends Eunuch{//错误
}
final修饰方法
表示这个方法不能被子类重写。
class Father{public final void method(){System.out.println("father");}
}
class Son extends Father{public void method(){//错误System.out.println("son");}
}
final修饰变量
final修饰某个变量(成员变量或局部变量),一旦赋值,它的值就不能被修改,即常量,常量名建议使用大写字母。
如果某个成员变量用final修饰后,并且必须初始化(可以显式赋值、或在初始化块赋值、实例变量还可以在构造器中赋值)
抽象类与抽象方法(或abstract关键字)
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
我们声明一些几何图形类:圆、矩形、三角形类等,发现这些类都有共同特征:求面积、求周长。那么这些共同特征应该抽取到一个共同父类:几何图形类中。但是这些方法在父类中又无法给出具体的实现
,而是应该交给子类各自具体实现。那么父类在声明这些方法时,就只有方法签名,没有方法体
,我们把没有方法体的方法称为抽象方法。Java语法规定,包含抽象方法的类必须是抽象类。
抽象类
[权限修饰符] abstract class 类名{}
[权限修饰符] abstract class 类名 extends 父类{}
抽象方法
抽象方法没有方法体和大括号
[其他修饰符] abstract 返回值类型 方法名([形参列表]);
1、抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
2、抽象类中,也有构造方法,是供子类创建对象时,初始化父类成员变量使用的。
3、抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
4、抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
5、不能用abstract修饰变量、代码块、构造器;不能用abstract修饰私有方法、静态方法、final的方法、final的类。
接口
在JDK8.0 之前,接口中只允许出现:
(1)公共的静态的常量:其中
public static final
可以省略(2)公共的抽象的方法:其中
public abstract
可以省略
类可以实现多个接口,一定程度上弥补了单继承的局限性
1、如果接口的实现类是非抽象类,那么必须
重写接口中所有抽象方法
2、默认方法可以选择保留,也可以重写
3、接口中的静态方法不能被继承也不能被重写
public class test {public static void main(String[] args){Bird bird = new Bird();bird.fly();System.out.println(bird.MIN_SPEED);}
}
interface flyable{ //接口public static final int MIN_SPEED = 0;public abstract void fly();
}
interface eatable{int mouth = 1;void eat();
}
class Bird implements flyable,eatable{@Overridepublic void fly() {System.out.println("鸟可以飞");}@Overridepublic void eat() {System.out.println("鸟可以吃东西");}
}
接口之间是可以继承的,且可以实现多继承,子接口没有什么限制,但是接入子接口的类必须重写所有接口的方法
interface flyable{public static final int MIN_SPEED = 0;public abstract void fly();
}
interface eatable{int mouth = 1;void eat();
}interface fly_and_eat extends flyable,eatable{}
接口的多态性
实现类实现接口,类似于子类继承父类,因此,接口类型的变量与实现类的对象之间,也可以构成多态引用。通过接口类型的变量调用方法,最终执行的是你new的实现类对象实现的方法体。
类似于类的多态性:
[接口] 接口名 = new [实现类]
先定义接口和类:
interface USB{void start();void end();
}class Computer{public void print(USB usb){ //形参是接口,但是传入实现类的对象usb.start();usb.end();}
}class Printer implements USB{@Overridepublic void start() {System.out.println("开始连接打印机");}@Overridepublic void end() {System.out.println("结束连接打印机");}
}
有三种实现多态的方法:
public class test {public static void main(String[] args){Computer computer = new Computer();Printer printer = new Printer();//创建接口实现类的对象computer.print(printer);//创建接口实现类的匿名对象computer.print(new Printer());//创建接口匿名实现类的对象USB usb = new USB() {@Overridepublic void start() {System.out.println("开始连接U盘");}@Overridepublic void end() {System.out.println("结束连接U盘");}};computer.print(usb);}
}
接口的默认方法
接口中的方法也可以有方法体,但是需要设置为 默认:
public class test {public static void main(String[] args){Printer printer = new Printer();printer.test();}
}
interface USB{public default void test(){System.out.println("默认方法的方法体");}
}class Printer implements USB{}
此处必须声明default,不能省略,否则会认为是 抽象方法
接口冲突:
若两个接口中定义了两个一样的默认方法,而实现类同时接入两个接口,就会产生接口冲突,该实现类需要重写该方法:
interface USB{public default void test(){System.out.println("默认方法的方法体");}
}
interface USB1{public default void test(){System.out.println("默认方法的方法体——2");}
}class Printer implements USB,USB1{@Overridepublic void test() {System.out.println("方法重写");}
}
但是如果其继承的父类也有一样的方法就没有问题,因为继承父类的优先级更高
interface USB{public default void test(){System.out.println("默认方法的方法体");}
}
interface USB1{public default void test(){System.out.println("默认方法的方法体——2");}
}class machine{public void test(){System.out.println("父类方法");}
}
class Printer extends machine implements USB,USB1{}
在实现类中也可以调用分别调用接口的方法
class Printer extends machine implements USB,USB1{@Overridepublic void test() {super.test();USB.super.test();USB1.super.test();
// 父类方法
// 默认方法的方法体
// 默认方法的方法体——2}
}
内部类
将一个类A定义在另一个类B里面,里面的那个类A就称为内部类(InnerClass)
,类B则称为外部类(OuterClass)
。
具体来说,当一个事物A的内部,还有一个部分需要一个完整的结构B进行描述,而这个内部的完整的结构B又只为外部事物A提供服务,不在其他地方单独使用,那么整个内部的完整结构B最好使用内部类。
分类:
成员内部类
public class test {public static void main(String[] args){//声明静态内部类person.man m1 = new person.man();//声明非静态内部类person p = new person();person.woman w1 = p.new woman();m1.eat();w1.eat();}
}
class person{static class man{public void eat(){System.out.println("man eat");}}class woman{public void eat(){System.out.println("woman eat");}}
}
显然静态成员内部类不能调用外部类的方法和属性
非静态成员内部类可以调用外部类的方法和属性,但是需要 person.this.xx
class person{public void showage(){System.out.println(this.age);}int age = 3;class woman{int age = 4;public void eat(){System.out.println("woman eat");}public void getage(){System.out.println(age); //4System.out.println(person.this.age);//3person.this.showage();//3}}
}
局部内部类
非匿名内部类:
public class test {public static void main(String[] args){person p = new person();eater m1 = p.get_a_man();m1.eat(); //man eatp.show_eat();//the man is eating}
}
interface eater{void eat();
}
class person{public eater get_a_man(){class man implements eater{public void eat(){System.out.println("man eat");}}return new man();}public void show_eat(){class man {public void eat(){System.out.println("the man is eating");}}new man().eat();}
}
上面写了两种情况,一种是返回了对象,一种是只有操作
对于返回对象的情况,必须要继承一个类或者接口,下面这种写法是无法调用到内部方法的:
class person{public Object get_a_man(){class man{public void eat(){System.out.println("man eat");}}return new man();}
}
匿名内部类:
使用匿名内部类的对象直接调用方法
public class test {public static void main(String[] args){new Object(){public void say(){System.out.println("hhhh");}}.say();}
}
通过父类或父接口的变量多态引用匿名内部类的对象
interface A{void say();
}public class test {public static void main(String[] args){A obj = new A(){public void say(){System.out.println("hhhh");}};obj.say();}
}
枚举类
枚举类型本质上也是一种类,只不过是这个类的对象是有限的、固定的几个,不能让用户随意创建。
例如星期的类,那么对象只会有7个
5.0之前,实际上就是在类内部自己定义好可能的对象,并设置为静态final对象
public class test {public static void main(String[] args){System.out.println(Season.SPRING.toString());//Season{SEASONNAME='春天', SEASONDESC='春暖花开'}}
}class Season{private final String SEASONNAME;//季节的名称private final String SEASONDESC;//季节的描述private Season(String seasonName,String seasonDesc){this.SEASONNAME = seasonName;this.SEASONDESC = seasonDesc;}public static final Season SPRING = new Season("春天", "春暖花开");public static final Season SUMMER = new Season("夏天", "夏日炎炎");public static final Season AUTUMN = new Season("秋天", "秋高气爽");public static final Season WINTER = new Season("冬天", "白雪皑皑");@Overridepublic String toString() {return "Season{" +"SEASONNAME='" + SEASONNAME + '\'' +", SEASONDESC='" + SEASONDESC + '\'' +'}';}
}
jdk5.0中,可以使用enum声明
- 枚举类的常量对象列表必须在枚举类的首行,因为是常量,所以建议大写。
- 列出的实例系统会自动添加 public static final 修饰。
- 如果常量对象列表后面没有其他代码,那么“;”可以省略,否则不可以省略“;”。
- 编译器给枚举类默认提供的是private的无参构造,如果枚举类需要的是无参构造,就不需要声明,写常量对象列表时也不用加参数
- 如果枚举类需要的是有参构造,需要手动定义,有参构造的private可以省略,调用有参构造的方法就是在常量对象名后面加(实参列表)就可以。
- 枚举类默认继承的是java.lang.Enum类,因此不能再继承其他的类型。
- JDK5.0 之后switch,提供支持枚举类型,case后面可以写枚举常量名,无需添加枚举类作为限定。
public class test {public static void main(String[] args){System.out.println(SeasonEnum.SPRING.getSeasonName());}
}
enum SeasonEnum {SPRING("春天","春风又绿江南岸"),SUMMER("夏天","映日荷花别样红"),AUTUMN("秋天","秋水共长天一色"),WINTER("冬天","窗含西岭千秋雪");private final String seasonName;private final String seasonDesc;private SeasonEnum(String seasonName, String seasonDesc) {this.seasonName = seasonName;this.seasonDesc = seasonDesc;}public String getSeasonName() {return seasonName;}public String getSeasonDesc() {return seasonDesc;}
}
enum常用方法:
public class test {public static void main(String[] args){System.out.println(SeasonEnum.SUMMER);System.out.println(SeasonEnum.SPRING.name());SeasonEnum[] values = SeasonEnum.values();System.out.println(Arrays.toString(values));
// SUMMER
// SPRING
//[SPRING, SUMMER, AUTUMN, WINTER]SeasonEnum s1 = SeasonEnum.valueOf("AUTUMN");System.out.println(s1);//Autumn}
}
实现接口的枚举类
每个对象单独重写接口方法
interface season_desc{void show();
}
enum SeasonEnum implements season_desc{SPRING("春天","春暖花开"){public void show(){System.out.println("春天在哪里?");}},SUMMER("夏天","夏日炎炎"){public void show(){System.out.println("宁静的夏天");}},AUTUMN("秋天","秋高气爽"){public void show(){System.out.println("秋天是用来分手的季节");}},WINTER("冬天","白雪皑皑"){public void show(){System.out.println("2002年的第一场雪");}};private final String seasonName;private final String seasonDesc;private SeasonEnum(String seasonName, String seasonDesc) {this.seasonName = seasonName;this.seasonDesc = seasonDesc;}
}
注解(Annotation)
注解(Annotation)是从JDK5.0
开始引入,以“@注解名
”在代码中存在。例如:
@Override
@Deprecated
@SuppressWarnings(value=”unchecked”)
注解是可以被编译器或其他程序读取的。程序还可以根据注解的不同,做出相应的处理。
@author 标明开发该类模块的作者,多个作者之间使用,分割 @version 标明该类模块的版本 @see 参考转向,也就是相关主题 @since 从哪个版本开始增加的 @param 对方法中某参数的说明,如果没有参数就不能写 @return 对方法返回值的说明,如果方法的返回值类型是void就不能写 @exception 对方法可能抛出的异常进行说明 ,如果方法没有用throws显式抛出的异常就不能写
@Override
: 限定重写父类方法,该注解只能用于方法
@Deprecated
: 用于表示所修饰的元素(类,方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择
@SuppressWarnings
: 抑制编译器警告
包装类
为了使得基本数据类型具备引用数据类型的相关特征
也就是把基本数据类型转换为 obj
public static void main(String[] args){int num = 520;Integer obj = new Integer(520);
}
相互转换:
1、将基本数据类型转换为引用数据类型
Integer a = Integer.valueOf(10);System.out.println(a);//3Float b = Float.valueOf(12.3f);System.out.println(b);//12.3Float c = Float.valueOf("12.4f");System.out.println(c); //12.4Boolean d = Boolean.valueOf("sad");System.out.println(d);//false
2、将引用数据类型转换为基本数据类型
Integer a = Integer.valueOf(10);System.out.println(a.intValue());Float b = Float.valueOf(12.3f);System.out.println(b.floatValue());
3、自动转换
由于我们经常要做基本类型与包装类之间的转换,从JDK5.0
开始,基本类型与包装类的装箱、拆箱动作可以自动完成。例如:
Integer a = 1;Float b=3.13f;Boolean c = true;int d = a;float e = b;boolean f = c;
包装类的其它API
数据类型的最大最小值
Integer.MAX_VALUE和Integer.MIN_VALUELong.MAX_VALUE和Long.MIN_VALUEDouble.MAX_VALUE和Double.MIN_VALUE
字符转大小写
Character.toUpperCase('x');Character.toLowerCase('X');
整数转进制
Integer.toBinaryString(int i) Integer.toHexString(int i)Integer.toOctalString(int i)
比较的方法
Double.compare(double d1, double d2)Integer.compare(int x, int y)
包装类对象的特点
Integer a = 1;
Integer b = 1;
System.out.println(a == b);//trueInteger i = 128;
Integer j = 128;
System.out.println(i == j);//falseInteger m = new Integer(1);//新new的在堆中
Integer n = 1;//这个用的是缓冲的常量对象,在方法区
System.out.println(m == n);//falseInteger x = new Integer(1);//新new的在堆中
Integer y = new Integer(1);//另一个新new的在堆中
System.out.println(x == y);//falseDouble d1 = 1.0;
Double d2 = 1.0;
System.out.println(d1==d2);//false 比较地址,没有缓存对象,每一个都是新new的
Integer i = 1000;
double j = 1000;
System.out.println(i==j);//true 会先将i自动拆箱为int,然后根据基本数据类型“自动类型转换”规则,转为double比较Integer i = 1000;
int j = 1000;
System.out.println(i==j);//true 会自动拆箱,按照基本数据类型进行比较Integer i = 1;
Double d = 1.0
System.out.println(i==d);//编译报错
包装类对象不可变
public class TestExam {public static void main(String[] args) {int i = 1;Integer j = new Integer(2);Circle c = new Circle();change(i,j,c);System.out.println("i = " + i);//1System.out.println("j = " + j);//2System.out.println("c.radius = " + c.radius);//10.0}/** 方法的参数传递机制:* (1)基本数据类型:形参的修改完全不影响实参* (2)引用数据类型:通过形参修改对象的属性值,会影响实参的属性值* 这类Integer等包装类对象是“不可变”对象,即一旦修改,就是新对象,和实参就无关了*/public static void change(int a ,Integer b,Circle c ){a += 10;
// b += 10;//等价于 b = new Integer(b+10);c.radius += 10;/*c = new Circle();c.radius+=10;*/}
}
class Circle{double radius;
}