自动拆装箱
8种基本类型与其对应包装器类型可以直接互换,8种基本类型与其对应包装类分别为
基本类型 包装类
short Short
int Integer
long Long
float Float
double Double
byte Byte
char Character
boolean Boolean
自动拆装箱概述
在JDK1.5之后,Java允许把基本类型与其对应的包装器类型之间自动相互转换。
自动装箱:Integer i =100; 把int类型之间赋值给Integer类型;
自动拆箱:int i =new Integer(100); 把Integer类型直接赋值给int类型
自动拆装箱原理
自动拆装箱是由编译器完成的,编译器编译代码时把 Integer i = 100; 加工为Integer i = Integer.valueOf(100); 把int a = i; 加工为 int a = i.intValue();
自动拆装箱演变题目
Integer i1 = 100;
Integer i2 = 100;
boolean b1 = i1 == i2;//结果为true
Integer i3 = 200;
Integer i4 = 200;
boolean b2 = i3 == i4;//结果为false
为什么会出现这种情况呢?上面我们说到,Integer i1 = 100;这是java1.5新特性自动装箱,实际上是编译器加工为 Integer i1 = Integer.valueOf(100);那么现在的问题就是,为什么i1,i2是同一个对象,而i3,i4不是同一个对象?
问题出在Integer.valueOf()方法,Integer类的内部缓存了从-128到127的256个Integer对象,如果valueOf()方法需要把这个范围之内的整数转换成Integer对象时,valueOf不会去new对象,而是从缓存中直接获取,这就会导致valueOf(100)方法执行两次,都是从缓冲中获取同一个Integer对象。如果valueOf()方法收到的参数不在缓存范围之内,那么valueOf()方法会new一个新对象,所以执行两次valueof(200),就会new两个对象,两个对象当然不同,所以i3 != i4,b2为false,而b1为true。
自动拆装箱演变题目2
Integer i1 = 59;
int i2 = 59;
Integer i3 = Integer.valueOf(59);
Integer i4 = new Integer(59);
System.out.println(i1 == i2);//true
System.out.println(i1 == i3);//true(自动拆箱)
System.out.println(i3 == i4);//false
System.out.println(i2 == i4);//true(自动拆箱)
分析:
Integer i1 = 59; 如同上面分析,调用Integer的valueOf方法,返回一个Integer对象i1。
int i2 = 59; i2是一个基本类型,存储在栈中。
Interger i3 = Integer.valueOf(59); 如同上面分析,可以知道返回缓存中已经存在的Integer对象,i1 == i3
Integer i4 =new Integer(59); 直接创建一个新的Integer对象。由此可知,i4对象和i1,i3不相等,因为不是同一个对象。
System.out.println(i1 == i2); 当包装器类型和基本数据类型进行“==”比较时,包装器类型会自动拆箱为基本数据类型。i1是Integer对象,而i2是基本类型int,所以这里比较的不是地址,而是值。Integer会自动拆箱为int,然后进行比较,所以i1和i2相同。
System.out.println(i1 == i3); 与上面分析的结果相同,结果为true
System.out.println(i3 == i4); 与上面分析的结果相同,结果为true
System.out.println(i2 == i4);当包装器类型和基本数据类型进行“==”比较时,包装器类型会自动拆箱为基本数据类型。i4是Integer对象,而i2是基本类型int,所以这里比较的不是地址,而是值。Integer会自动拆箱为int,然后进行比较,所以i4和i2相同。
注意:八种类型除了double和float类型的包装类valueOf方法没有缓存对象,其他6种都有缓存对象。
可变参数
可变参数就是一个方法可以接收多个参数,例如:func(1,2,3,...)
定义可变参数方法
pubic void func(int... arr){} 上面方法func()的参数类型为int..., 其中“...”不是省略号,而是定义参数类型的方式。参数arr就是可变参数类型,可以理解为public void fun(int[] arr), 所以可以理解为int... 是一种新的定义数组形参的方式,代替int[],但是注意只有在方法的形参中可以使用"...",可变参数其实就是数组类型,只不过在调用方法的时候更方便一些,由编译器帮我们把多个实参放到一个数组中传递给形参。
可变形参方法的限制
一个方法最多只能有一个可变参数。
可变参数必须是方法的最后一个参数。
增强for循环
增强for循环是for的一种新用法,用来循环遍历数组和集合。
增强for的语法
for(元素类型 e: 数组或者集合对象){}例如:
int[] array={1,2,3};
for(int i : array){
System.out.println("i = " + i);
}
增强for循环的冒号左边是定义变量,右边必须是数组或者集合类型。for循环内部会依次把array数组中的元素赋值给变量i。
增加for的优缺点
只能从头到尾的遍历数组或集合,而不能只遍历部分;
在遍历List或数组时,不能获取当前元素下标;
增强for使用便简单,这是它唯一的优点了;
增强for比使用迭代器方便
增强for原理
任何实现了Iterable接口的类,都有返回Iterator的方法,增强for的底层就是迭代器,任何实现了Iterable接口的类,都可以使用增强for来遍历,但是注意Map并没有实现Iterable接口,所以不能直接使用增强for遍历。下面是一个实现Iterable接口使用增强for循环遍历的例子:
import org.junit.Test;
import java.util.Iterator;
public class Demo3 {
@Test
public void func(){
Word word = new Word("abcd edf hijk lmn");
for(String s: word){
System.out.println(s);
}
}
}
class Word implements Iterable{
private String text;
public Word(String s){
this.text=s;
}
@Override
/*
* 希望每次遍历一个单词
*/
public Iterator iterator() {
return new Iterator() {
private String[] wordArray = text.split("\\s+");
private int index =0;//表示从0下标开始遍历
@Override
public boolean hasNext() {
return index < wordArray.length;
}
@Override
public String next() {
return wordArray[index++];
}
};
}
}
泛型
泛型概述
泛型是JDK5.0的新特性,主要应用在集合类上。有了泛型之后,集合类与数组就越来越像了。例如:Object[] objs = new Object[10], 可以用来存储任何类型的对象。 String{} strs = new String[10]就只能用来存储String类型的对象。
同样的,ArrayList list =new ArrayList()可以用来存储任何类型的对象。ArrayList list = new ArrayList()就只能用来存储String类型的对象。
理解泛型类
具有一个或多个类型变量的类称之为泛型类
泛型类具有一个到多个泛型变量,在创建泛型类对象时,需要为泛型变量知道值。泛型变量只能赋值为引用类型,而不能是基本类型。例如ArrayList类中有一个泛型变量E,在创建ArrayList类的对象时需要为E这个泛型变量指定值。下面是一个泛型类的创建和使用。
import org.junit.Test;
/**
* 创建泛型类
*/
public class Demo4 {
@Test
public void func(){
A a1 =new A();//创建对象时给类型变量赋值
A a2 = new A();//每个对象可以给出不同的值
}
}
/*
* 类名称后给出尖括号,尖括号内给出类型变量
* 如果是多个类型变量,使用逗号分隔
* 命名要求:单个大学字母
* 参数化类型:A
* 类型变量:T,它是一个变量,需要赋类型值。
*/
class A {
/*
* 在类内,可以使用类型变量,在以下位置可以使用:
* * 实例成员类型上
* * 实例方法参数和返回值上
* * 构造器的参数类型上
*
* * static的成员和方法上不能使用类型变量T
*/
private T t;
public A(T t){
this.t = t;
}
public A(){
}
public T getT(){
return this.t;
}
public void setT(T t){
this.t = t;
}
}
使用泛型对象
创建泛型对象时,引用和new两端的泛型类型需要一致,比如:List list = new ArrayList();两端都需要是String类型,如果不一致就会出错。eg: List list = new ArrayList();//编译失败!
泛型的好处
将运行期遇到的问题转移到了编译期
泛型不可能去除所有类型转换,但可以减少类型转换操作
在循环遍历集合类时,方便了很多
一定程度上提高了安全性
泛型方法定义
不只可以创建泛型类,还可以创建泛型方法。泛型方法不受类的限制,即为,方法所在类即使不是泛型类,也可以有泛型方法。定义泛型方法的格式:修饰符 返回值 方法名
一般泛型方法的特点:
返回值会使用泛型
在参数中会使用泛型 下面是一个使用泛型方法的例子:
package oneday.one;
import org.junit.Test;
/**
* Created by ZPF on 2019/10/29.
*/
public class Demo5 {
@Test
public void func1(){
// String name = AA.get(new String[] {"zhangsan", "lisi", "abc", "def"});
String name = AA.get(new String[] {"zhangsan", "lisi", "abc", "def"});
System.out.println(name);
}
}
class AA{
/*
* 泛型方法不受类的限制,即为,方法所在类即使不是泛型类,也可以有泛型方法
*/
/*
* 定义泛型方法的格式:
* 修饰符 返回值 方法名
* 一般泛型方法的特点:
* * 返回值会使用泛型
* * 在参数中会使用泛型
*/
//显示数组中间值
public static T get(T[] array){
return array[array.length/2];
}
}
ArrayList类中的toArray方法也是泛型方法:
/*如果传入数组的长度小于size,返回一个新的数组,大小为size,类型与传入数组相同。
所传入数组长度与size相等,则将elementData复制到传入数组中并返回传入的数组。
若传入数组长度大于size,除了复制elementData外,还将把返回数组的第size个元素置为空。
其中:elementData存储ArrayList内的元素,size表示它包含的元素的数量,都是ArrayList的属性。*/
public T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a‘’s runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
泛型擦除
泛型是编译器状态,所有的泛型会被编译器擦除,变成了Object类型!
编译器会在适当的位置上添加强制转化。
继承(或实现)泛型类(或接口)
import org.junit.Test;
public class Demo6 {
@Test
public void func2(){
BB bb =new BB();
bb.setBean("hello");//参数必须是“String”类型
BBB bbb = new BBB<>();
bbb.getBean();//返回值是Integer类型
}
}
class B {
private T bean;
public T getBean(){
return bean;
}
public void setBean(T t){
this.bean = t;
}
}
/*
* BB类不是泛型类,但是它的父类是泛型类
* 如果父类是泛型类,那么子类在继承时需要给父类传递类型变量值!(比如:下面的BB类传递了String)
* 例如BB类,它所继承的是B,也就是说,在父类出现的所有T等同与String
*/
class BB extends B{
}
/*
* BBB类也是一个泛型类,它继承了父类泛型类
* 给父类传递的是自己的泛型
*
*/
class BBB extends B {
}
class MyComparable implements Comparable{
@Override
public int compareTo(String o) {
return 0;
}
}