1.Switch- case
switch(表达式)
{ case 常量表达式1:语句1;
.... case 常量表达式2:语句2;
default:语句; }
1、表达式值可以是 byte、short、int、char 从javaSE7之后可以使用String(编译时使用字符串hash值实现)
2、case后语句可以不用大括号
3、如果匹配到case,name会顺序执行之后的语句(包括default也按顺序执行),直到遇到break
————————————————
版权声明:本文为CSDN博主「三朵耳朵」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37499840/article/details/90075661
2.内存单位:
位=bit=binary digit ==八分之一字节(byte)=十六分之一字(代表一个汉字)
3. 变量
- 引用变量
- 基本数据类型
Byte类型( 1 byte)、 short(2 byte)、 int (4byte)、 float (4 byte)、 long(8byte) double (8byte),
字符型( 2 Byte)
整数型;默认 int ,浮点型,默认 double
或分为:
- 成员变量(作用域比局部变量大),可以不用初始化。其中Static 修饰的是静态变量,普通的就是成员变量。静态变量。多个实例共享一份变量,可用类名进行引用。注意: 类的静态变量在内存中只有一个,java虚拟机在加载类的过程中为静态变量分配内存,静态变量位于方法区,被类的所有实例共享。静态变量可以直接通过类名进行访问,其生命周期取决于类的生命周期。而实例变量取决于类的实例。每创建一个实例,java虚拟机就会为实例变量分配一次内存,实例变量位于堆区中,其生命周期取决于实例的生命周期。
加载类;
静态变量初始化;
静态块;【其只能调度静态的,不能调度非静态的】
成员变量;
构造方法;
静态成员变量的详解:https://www.cnblogs.com/liuguoguo/p/8525220.html
- 局部变量,必须要初始化。
类型转化问题:
- 高精度——>低精度转化需要强制类型转换,如果不写的话会强制报错的
- 低精度——>高精度 自动完成
- 如果高精度->低精度,右边的是常数(高精度),判断该常数范围是不是在小精度的范围里面,这样就可以自动提升 eg: byte b=3; 反例如果byte b=b+3,就会报错,因为不清楚b的取值范围
- int 和 float做运算,结果是 float
- char可以和整形相互转换,做运算,,相当于char的底层还是数字,用编码表将他转换显示出来。'a'+1 打印结果是98,如果需要字符,再强制转换
4. 运算符
|和|| 右边这个会短路。左边判断完了,如果为真就不判断右边了
? 下图的符号运算优先级有点头皮发麻
判断表达式? A(表达式) :B(表达式); 可以赋值给一个变量
true ^ true = false;
true ^ false = true;
false ^ true = true;
false ^ false = false;
^异或的运算规律: ^符号的两边结果如果相同,结果是false, 两边的结果不同,结果是true。
5. 进制
以2进制为基准,1个bit为单位为2进制,3bit为单位是 8进制,生活场景使用的是十进制,4bit为基准为16进制。进制之间的转换以2进制为桥梁(如十进制90转成-0101-1010转化为16
进制,每三个bit变成十进制,然后连起来就可以)
负数表现形式:原数取反+1
移位:
往左移X,<<,其实启动过程像是往右边移动,乘以2的X倍
往右移X,<<,其实启动过程像是往左边移动,除以2的X倍 (往前面补齐位数的时候,补的是原有数据的最高位置(0/1)来补充)
<<< 无论最高位是什么,都用0来补
&:有假为假,
|: 有真为真
^ 异或:两边相同为假,反之为真
一个数异或一个数两次,结果还是那个数
可以用异或,从2进制转换为16进制:首先异或15(与1111(十进制中的15进行异或,得到末尾4位的位1的值;利用左移功能循环取其他剩下的位当中位1的值))
6 循环
for 和 while
for中的循环标记量是局部变量
while中的循环标记量是全局变量
W: for() W:表示给循环起名字,
break 只是跳出最内层循环(不循环了,continue停止本次,break停止所有的循环),如果 break W, 表示跳出标号为W的循环(break可用于循环和switch)
continue 也可以使用循环标号
注意: 增强for循环格式:for(变量类型 变量名:被遍历的数组)
7.数组和内存
方法:开辟的空间是在stack内存里面,其中的局部变量也在里面,当函数执行完毕这部分内存就会消失。数据使用完,空间自动释放。(局部变量都在栈内存里面)
实体(包括数组和对象):都在堆里,new出来的东西都放在堆里。
堆内存三个特点:
- 垃圾自动回收
- 内存地址值
- 自动初始化
自动释放
内存的分类:
1.栈2. 堆3.方法区4.
栈空间的a赋值给b(基本数据类型,没有指向地址),则值复制一份给b,a的值不变,改变b的值,a也没发生改变
冒泡排序:相邻两个元素进行比较,换位置,这样最右边的就是最值了。经过多次之后顺序就排完了
选择排序:每一轮数组的首个元素和剩下的不断比较
Arrays.sort();//利用模块中现成的方法排序
折半查找:
8. 面向对象:
匿名对象:new Car().run();
- 当对象对方法仅进行一次调用的时候,就可以简化成匿名对象。
- 匿名对象可以作为实际参数进行传递
private: 修饰成员,权限只在本类里面可以获取
構造方法:可以有修饰符,没有返回值。
静态代码块:和函数代码块同一级别
随着类的加载而执行。而且只执行一次。
作用: 用于给类进行初始化
static
{
num = 10; // num *=3;
System.out.println("hahahah");
}
构造代码块。可以给所有对象进行初始化的。与函数同一级别
{
System.out.println("constructor code ");
// cry();
}
1,局部代码快。 对局部变量的生命周期进行控制。如if语句框
2,构造代码块。 对所有对象进行初始化。
3,静态代码块。 对类进行初始化。
static 静态关键字用法详解:
1,static是一个修饰符,用于修饰成员
2.static修饰的成员被所有的对象所共享。
3,static优先于对象存在,因为static的成员随着类的加载就已经存在了。
4,static修饰的成员多了一种调用方式,就可以直接被类名所调用 。 类名.静态成员 。
5,static修饰的数据是共享数据,对象中的存储的是特有数据。
成员变量和静态变量的区别?
1,两个变量的生命周期不同。 成员变量随着对象的创建而存在,随着对象的被回收而释放。 静态变量随着类的加载而存在,随着类的消失而消失。
2,调用方式不同。 成员变量只能被对象调用。 静态变量可以被对象调用,还可以被类名调用。
3,别名不同。 成员变量也称为实例变量。 静态变量称为类变量。
4,数据存储位置不同。 成员变量数据存储在堆内存的对象中,所以也叫对象的特有数据. 静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据.
静态使用的注意事项:
1,静态方法只能访问静态成员。(非静态既可以访问静态,又可以访问非静态)
2,静态方法中不可以使用this或者super关键字。
3,主函数是静态的
this 关键字的用法:
1.this可以区分成员变量与局部变量
class Person
{
private String name;
private int age;
Person(String name)
{
//成员变量和局部变量重名,可以用关键字this区分
this.name = name;
}
public void speak()
{
//输出时,会默认为成员增加this关键字,用来代表具体对象的数据 System.out.println(this.name+":"+this.age);
}
}
2.this也可以用于在构造函数中调用其他构造函数。
3.this 指代调用函数的当前
类有默认的不带参数的构造函数,如果显示的写了带参数的构造函数,则这个不带参数的会被覆盖,此时若再调用无参数的构造函数,则会报错。
构造函数没有 具体的返回值。但是,没有 具体的返回值。但是,没有 具体的返回值。但是,没有 具体的返回值。但是,没有 具体的返回值。但是,没有 具体的返回值。但是,没有 具体的返回值。但是returnreturn return return语句,用于结束构造函数。 语句,用于结束构造函数。 语句,用于结束构造函数。 语句,用于结束构造函数。 语句,用于结束构造函数。 语句,用于结束构造函数。 语
9 继承
假设classB extends classA , 子类的所有构造函数(包括无参构造函数,有参构造函数),如果不是显式调用哪种超类构造函数,都会默认调用super(),即:父类的无参构造函数,如果此时父类中没有无参构造函数的话,报错~ 建议父类也添加一个无参构造函数 。
注:子类自定义有参数的构造函数的时候,需要写个super(且保证能够对应的上父类的构造函数,如果super没有带参数,则父类需要有无参数的构造函数,如果没有,则需要在super()加上目前有的父类的参数);不显示的构造函数会自动调用super()。
在深度继承关系中,即当存在C继承B,B继承A,或者更多层继承时,首先执行最上层的构造函数,再依次顺着继承链传递下去,一直到 创建对象的那个类。例如:我们声明C对象时,调用的是C的构造函数c,构造函数c调用的是父类B的构造函数b,构造函数b调用
继承&构造凼数:
/* 子父类中的构造函数的特点。 在子类构造对象时,发现,访问子类构造函数时,父类也运行了。 为什么呢? 原因是:在子类的构造函数中第一行有一个默认的隐式语句。 super(); 子类的实例化过程:子类中所有的构造函数默认都会访问父类中的空参数的构造函数。
为什么子类实例化的时候要访问父类中的构造函数呢? 那是因为子类继承了父类,获取到了父类中内容(属性),所以在使用父类内容之前, 要先看父类是如何对自己的内容进行初始化的。 所以子类在构造对象时,必须访问父类中的构造函数。 为什么完成这个必须的动作,就在子类的构造函数中加入了super()语句。
如果父类中没有定义空参数构造函数,那么子类的构造函数必须用super明确要调用 父类中哪个构造函数。同时子类构造函数中如果使用this调用了本类构造函数时, 那么super就没有了,因为super和this都只能定义第一行。所以只能有一个。 但是可以保证的是,子类中肯定会有其他的构造函数访问父类的构造函数。
注意:supre语句必须要定义在子类构造函数的第一行。因为父类的初始化动作要先完成。 */
单例模式:
1.饿汉式,类一加载,对象就存在。使用private 静态类变量创建一个对象,然后通过一个公有静态函数将他返回出来。
2.懒汉式,只有调用函数的时候,对象才能够生成,在调用函数的时候,需要判断该私有类变量(static)是否存在该类的对象,如果没有,才调用私有构造方法进行创建,最后将类变量实例传出去。
单例模式在内存中的体现:
首先涉及到三个区域:1.heap2.stack3.方法区
静态成员,静态成员的引用在stack里面,创建的对象是在在堆内存里面。
如图所示:
10. 抽象类
- 抽象类可以不包含抽象方法,,包含抽象方法的类一定是抽象类。
- 抽象类中有构造函数 ,用于给子类对象进行初始化。
- 方法只有声明没有实现时,该方法就是抽象方法,需要被abstract修饰。 抽象方法必须定义在抽象类中。该类必须也被abstract修饰。
- 抽象类必须有其子类覆盖了所有的抽象方法后,该子类才可以实例化。 否则,这个子类还是抽象类。
抽象关键字不可以和那些关键字共存?
private 不行(其实暗含着final的意思)
static 不行
final 不行
final关键字:
1,final是一个修饰符,可以修饰类,方法,变量。
2,final修饰的类不可以被继承。
3,final修饰的方法不可以被覆盖。
4,final修饰的变量是一个常量,只能赋值一次。 为什么要用final修饰变量。其实在程序如果一个数据是固定的, 那么直接使用这个数据就可以了,但是这样阅读性差,所以它该数据起个名称。 而且这个变量名称的值不能变化,所以加上final固定。
11.接口(interface)
- 类与类之间是继承关系,类与接口直接是实现关系。
- 接口不可以实例化。
只能由实现了接口的子类并覆盖了接口中所有的抽象方法后,该子类才可以实例化。 否则,这个子类就是一个抽象类。
- 接口中的成员都是公共的权限
- 当一个抽象类中的方法都是抽象的时候,这时可以将该抽象类用 另一种形式定义和表示,就是接口 interface。(接口里面不能有非抽象方法)
- 接口的出现避免了单继承的局限性
- 接口可以继承接口,多继承接口也可。类可以多实现多个接口
interface MM { void method(); }
interface QQ extends CC,MM//接口与接口之间是继承关系,而且接口可以多继承。
{
void function();
}
class WW implements QQ
{
//覆盖3个方法。
public void show(){} public void method(){} public void function(){}
}
接口和抽象类异同点:
相同点: 都是不断向上抽取而来的。
不同点:
1,抽象类需要被继承,而且只能单继承。 接口需要被实现,而且可以多实现。
2,抽象类中可以定义抽象方法和非抽象方法,子类继承后,可以直接使用非抽象方法。 接口中只能定义抽象方法,必须由子类去实现。
3,抽象类的继承,是is a关系,在定义该体系的基本共性内容。 接口的实现是 like a 关系,在定义体系额外功能
12. 多态
关键字:instanceof,用于判断对象的具体类型。只能用于引用数据类型判断
a instanceof Cat
体现:父类或者接口的引用指向其子类的对象;
Animal a=new Cat();
a.eat()调用的是子类的eat()//根据函数的复写特点
多态的成员变量的特点:
1.对于成员方法,在多态中,父类引用指向子类对象,编译的时候,看的是父类是否包含这几个方法;运行的时候,子类和父类都有的方法,运行子类的复写的方法;如果子类没有改写,就调用从父类继承来的函数
2.对于成员变量,在多态中,父类引用指向子类对象,编译和运行的时候,都看的是父类的(假如父类和子类都有num对象)
如果父类有空参数的构造方法,则子父类的构造函数同一个参数进行参数共享。(不是像之前一样只看父类了)
在多态中,子类父类名字参数一样,返回值不一样,这样不能重载也不能重写,因此会编译失败。
3.对于静态函数和成员,编译和运行结果都参考左边
动态绑定和静态绑定
多态转型:
1.向上转型,类比于基本数据类型,精度自动提升,从小范围,到大范围
Animal a=new Cat();
只能调用父类中有的成员,结果是子类重载的结果,如果调用了子类的特有方法会报错。
2.向下类型转换
Cat c=(Cat)a
不能未卜先知。先要有多态关系。
此时可以调用子类特有方法
多态自始自中都是对象在发生改变
毕老师 和毕姥爷的例子
多态的前提:
1.类之间实现了继承或者实现
2.方法之间存在覆盖
多态的弊端:
只能预先用父类的引用访问父类中的成员。
目的:
1.增加了代码的复用性
11.Object 类
equals()方法,比较对象时,比较地址是否相同,等价于==
对equals()需要修改他的比较方式:
1.在待使用的类里面重写 compare()方法
2.重写 equals方法,注意(1.用多态向下转型用子类当中的成员变量,在此例子中,Object没有num属性2.注意判断 是不是相同的类之间比较)
toString()方法一般需要重写;
13 内部类:
1.作用:避免多生成一些不必要的对象,为了使用对象里面的某些值
2.用法:
- 内部内可以直接访问外部类的成员变量,不用生成对象。eg:孙悟空进入牛魔王体 内, 原因,内部类中持有外部类的引用Outer.this(自动有的);
- 外部类访问内部类需要生成内部类的对象。
- 访问内部类可以:Outer.Inner (类型)xx=new Outer(). new Inner( ) (类型);
- 定位和成员变量差不多,可以用private等修饰符修饰,其实还可以放在局部
- 用处:当描述事物里面还有事物,并且内部这个还访问外部的资源
- 局部不能被static修饰?????? 局部内部内不能定义静态成员
内部类定义在局部的时候:
1.任然可访问成员变量
2.不可以被成员修饰符所修饰
3.不能访问它所存在的局部的变量,除了访问里面带有final修饰符的
4.
匿名内部类:
記住匿名内部類調用完函數之後需要加上分號,如果是匿名内部類的最先開始定義,則記住不要加分號;
14. 异常类
非运行时异常,提示可能会出错,但是不一定出错,这样的情况他提示错误,最好用,try catch 语句块进行 处理一下
有的异常结果,我们没有权限处理,不能用 try catch
这时可以用 throws进行处理://仅仅是抛给调用者,谁调用,谁处理,甩锅
定义方法 方法名字 throws 异常类名
{
}
运行时异常也可以用 try catch 和 throws方法进行处理,但是处理意义并不是很大,还得回去修改代码
自定义异常:
继承Exception类, 方法体内throw 一个异常,方法定义上需要throws 一个异常出去,告诉别人这里可能会出异常。
继承Runtime Exception :方法体上可以不用 throws 抛出,如果有问题JVM会自动抛出
补充,try catch 语句块,try里面出错的话,从错误的地方就不执行了,就去找catch语句块对应的类型,finally一定可以执行到的。
异常处理的原则:
1,函数内容如果抛出需要检测的异常,那么函数上必须要声明(Throws)。 否则必须在函数内用trycatch捕捉,否则编译失败。
2,如果调用到了声明异常的函数,要么trycatch要么throws,否则编译失败。
3,什么时候catch,什么时候throws 呢? 功能内容可以解决,用catch。 解决不了,用throws告诉调用者,由调用者解决 。
说明:如果该功能内部可以将问题处理,用 try,如果处理不了,交由调用者处理,这是用 throws 区别: 当前程序需要继续运行就 try 当前程序不需要继续运行就throws
举例:
感冒了就自己 吃点药就好了,try
吃了好几天药都没好,结果得了 H7N9,那就得 throws到医院去对人进行 治疗
如果医院没有特效药,就变成 Error 了
4,一个功能如果抛出了多个异常,那么调用时,必须有对应多个catch进行针对性的处理。 内部又几个需要检测的异常,就抛几个异常,抛出几个,就catch几个。catch里面的代码出错了之后会全部执行完。
子类覆盖父类只能抛出父类的异常或者子类或者子集。 注意:如果父类的方法没有抛出异常,那么子类覆盖时绝对不能抛,就只能try
因为 什么自定义的结果都没输出,直接就抛异常了
另外一个13题,标识了异常。但是不一定出异常,结果又可能执行到,所以是能够编译。
内心OS(难道Try里面不可能输出自定义内容就会编译失败吗毕向东125Video)
throw break,return下面不要定义语句,因为执行不到
try或者
catch里面有return,也有finally,先把try,catch里面的东西执行完,再去执行finally里面的东西,执行完了之后执行之前的return,try catch finally体系后面的代码不执行了
多线程:
开启方式
1 创建Thread的子类,再把自定义代码放在run里面。start创建并启动线程(run的话不能直接启动线程,只能像调用函数一样调用)
2. 实现Runable 接口,重写run()方法,创建Thread 对象
创建线程的第一种方式:继承Thread类。 创建线程的第二种方式:实现Runnable接口。
1,定义类实现Runnable接口。
2,覆盖接口中的run方法,将线程的任务代码封装到run方法中。
3,通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。 为什么?因为线程的任务都封装在Runnable接口子类对象的run方法中。 所以要在线程对象创建时就必须明确要运行的任务。
4,调用线程对象的start方法开启线程。
实现Runnable接口的好处:
1,将线程的任务从线程的子类中分离出来,进行了单独的封装。 按照面向对象的思想将任务的封装成对象。
2,避免了java单继承的局限性。 所以,创建线程的第二种方式较为常用。
线程的五大状态:
局部变量在每一个线程里面都会有一个独立的变量,互相不冲突
线程取名
1.super()构造函数
获取线程名字:
1静态方法。currentThread()
2.this
线程改名字
类.setName()
同一个线程对象不能多次Start(),否则线程会蒙
多线程的安全问题:
1.当在循环里面写上一个sleep,循环,对于成员变量,多线程分享同一份。局部变量每个线程各有各的。这样到sleep之后的代码会产生滞后性,因此可能会造成安全问题。
解决方法用同步代码块
synchronized(任意一个·对象 )
{
放需要处理共享数据的语句
}
原理:obj相当于一个锁(有当前进程,标志位就是0,别的进程就进不来,出来之后就变成1的标志位)
火车上的卫生间例子。
同步的好处:解决了线程的安全问题。
同步的弊端:相对降低了效率,因为同步外的线程的都会判断同步锁。
同步的前提:同步中必须有多个线程并使用同一个锁
同步可以作为修饰符,修饰函数,synchronized。作为修饰符。其中修饰函数的话,锁是this.
synchronized 放在run()上面,实际上只有一个线程正在运行。
函数被静态修饰,他的锁是Class类对象。字节码对象
类名.Class 该对象的类型是CLass
锁是针对当前线程来说的。嵌套锁的话容易造成死锁
线程之间的通信:
notify是唤醒等待时间最长的线程 wait()默认的锁是this. 使用在同步中
如果线程多了,需要操作同一个对象的不同方法,如果有不同步问题,可以采用notifyAall()和while(flag)循环判断问题。
对于生产者消费者的替代解决方法:
jdk1.5以后将同步和锁封装成了对象。
并将操作锁的隐式方式定义到了该对象中,
将隐式动作变成了显示动作。
Lock接口: 出现替代了同步代码块或者同步函数。将同步的隐式锁操作变成现实锁操作。
同时更为灵活。可以一个锁上加上多组监视器。
lock():获取锁。
unlock():释放锁,通常需要定义finally代码块中。
Condition接口:出现替代了Object中的wait notify notifyAll方法。
将这些监视器方法单独进行了封装,变成Condition监视器对象。
可以任意锁进行组合。
守护线程:也叫做后台线程,依赖于正常线程而存在,在线程启动前进行设置。如果线程全部是守护线程,则JVM会退出。
thread.setDaemon(true);
停止线程:
1.run方法的停止
特殊情况:1.停止run当中的循环,用状态标记变量进行停止(可采用设置一个方法控制该标记)
2.线程wait了,不可用notify去通知,因为当前的线程已经冻结了,得用外部的力(interrupt方法进行强制引起Exception异常,接着可以在catch里面改变状态值了)
yield方法。使得该线程对象暂时交出执行权,有利于线程之间的平衡性能。
多线程的使用场景:当代码之间需要独立运行互不相关的时候,可以用多线程,其中有个小tips。可以在类里面使用Runnable接口和Thread子类的匿名内部类创建多线程。毕向东第154集。
String 类
字符串是特殊的类
两种创建方法
1. String a="abc"
2String a=new String("abc")
特点:1.创建了之后就不会改变。
String a="abc"
a="kk"
打印a的话,啊
因为是类变量,他的指向变了,但是abc是不会变的
String s = "abc";//创建一个字符串对象在常量池中。
String s1 = new String("abc");//创建两个对象一个new一个字符串对象在堆内存中。 System.out.println(s==s1);//false System.out.println(s.equals(s1));
//string类中的equals复写Object中的equals建立了string类自己的判断字符串对象是否相同 的依据。
//其实就是比较字符串内容。
String s1 = "abc";//创建一个字符串对象在常量池中。
String s2 = new String("abc");//创建两个对象一个new一个字符串对象在堆内存中。
String s3="abc"
System.out.println(s1==s2);//false
System.out.println(s1==s3);//true。因为abc是放在常量池里面的,对象都是一样的,所以就不用开辟新的空间了。所以s1==s3
其中 注意==表示 对象是否相同的比较
常量池在内存中是在方法区域里面。
方法区包括:1.静态区域2.方法3.常量池
字符串中,String a="abc",相当于是把abc 分别放入内存当中的常量池里面去。
String类的常见方法:
spilt(参数是用来分割的模板符号)
如 "a-b-v".spilt(-)就根据-来分割字符串。
将其他类型的数据转换为String,valueOf()
StringBuffer:就是字符串缓冲区。 * 用于存储数据的容器。
* 特点:
* 1,长度的可变的。
* 2,可以存储不同类型数据。
* 3,最终要转成字符串进行使用。
* 4,可以对字符串进行修改。(修改之后,对象还是原对象(==的话会是true))
/* * jdk1.5以后出现了功能和StringBuffer一模一样的对象。就是StringBuilder * * 不同的是: * StringBuffer是线程同步的。通常用于多线程。
* StringBuilder是线程不同步的。通常用于单线程。 它的出现提高效率。
包装类:
基本类型--->字符串 *
1,基本类型数值+"" *
2,用String类中的静态方法valueOf(基本类型数值);
* 3,用Integer的静态方法valueOf(基本类型数值);
* * 字符串--->基本类型 *
1,使用包装类中的静态方法 xxx parseXxx("xxx类型的字符串");***** * int parseInt("intstring"); * long parseLong("longstring"); * boolean parseBoolean("booleanstring"); *
只有Character没有parse方法 *
2,如果字符串被Integer进行对象的封装。
* 可使用另一个非静态的方法,intValue();
* 将一个Integer对象转成基本数据类型值。
3.Integer有构造函数,将string可以搞成包装类,再通过包装类型转换。
注意:
Integer i1=new Integer("123")
Integer i2=new Integer(123)
i1和i2的==是false,两个对象
equals()已经被重写了,所以是内容一样,true
对于另一种情况:(以byte来衡量是否需要创建新的对象)
Integer a = new Integer(128); Integer b = new Integer(128); System.out.println(a==b);//false
System.out.println(a.equals(b));//true
Integer x = 129;//jdk1.5以后,自动装箱,如果装箱的是一个字节,那么该数据会被共享不会 //重新开辟空间。
Integer y = 129; System.out.println(x==y);//false
System.out.println(x.equals(y));//true