包装类
包装类是Java提供的一种特殊类,它们将Java的基本数据类型(如int、double、char等)封装成对象。这样做的好处是可以将基本数据类型作为对象来处理,使用对象所特有的属性和方法。
Java提供了8种基本数据类型的包装类:
Integer → int
Double → double
Byte → byte
Short → short
Long → long
Float → float
Character → char
Boolean → boolean
获取包装类对象的方式
使用valueOf()创建
以Integer为例,直接通过调用valueOf方法,把值传入到方法中
Integer i1 = Integer.valueOf(127);
下面看一个特殊的例子:
Integer i1 = Integer.valueOf(127); Integer i2 = Integer.valueOf(127); System.out.println(i1 == i2); // true Integer i3 = Integer.valueOf(128); Integer i4 = Integer.valueOf(128); System.out.println(i3 == i4); // false
对于引用数据类型,因为" == " 是比较地址值的,i3 , i4不是同一个对象可以理解,但是为什么 i1 和 i2 是一样的呢?
在实际开发中,-128~127之间的数字用的比较多,为了节省内存,Java提前创建好了这些对象,用的时候直接调取,不会再创建新的对象
直接赋值
自动装箱和自动拆箱
当使用包装类的时候,该怎么去进行计算呢,首先要把对象转化为基本数据类型,再进行计算,再转化为引用数据类型,这样手动的去转化就非常麻烦,所以在JDK5的时候就出现了自动装箱和自动拆箱的机制
自动装箱:把基本数据类型变为对应的包装类
自动拆箱:把包装类转化为对应的基本数据类型
//自动拆箱 Integer i = 1; //自动装箱 int j = i; System.out.println(i); System.out.println(j); System.out.println(i + j);
Integer成员方法
返回值为String类型
//进制转换 System.out.println(Integer.toBinaryString(10));//1010 System.out.println(Integer.toOctalString(10));//12 System.out.println(Integer.toHexString(10));//a
类型转换:
Integer i5 = Integer.parseInt("123"); System.out.println(i5 + 1); Scanner sc = new Scanner(System.in); String s = sc.nextLine();//键盘录入一行,遇到空格不会停止 System.out.println(s); System.out.println(Integer.parseInt(s) + 1);
除了 Character,都有对应的转换方法
泛型
在Java编程中,泛型是一个强大的工具,它允许我们在编写代码时定义灵活的、可重用的结构,而无需关心具体的数据类型。
引出泛型
问题:实现一个类,类中包含一个数组成员,使得数组中可以存放任意类型的数据,也可以根据成员方法访问返回数组中下标的值
如果是任意类型的话,可以考虑Object,因为它是所有类型的父类,接着试着实现一下这个问题
class MyArray{ private Object[] arr = new Object[10]; public void set(int index,Object value){ arr[index] = value; } public Object get(int index){ return arr[index]; } } public class Demo1 { public static void main(String[] args) { MyArray myArray = new MyArray(); myArray.set(0,"AA"); myArray.set(1,1); String s = (String) myArray.get(0);//因为返回的是Object类型,所以需要强制类型转换 int i = (int)myArray.get(1); System.out.println(s+" "+i); } }
上面的代码就实现了这个要求,但是此时发现一个弊端,如果数据过多的话就显得特别杂乱,各种类型都有,都需要强制类型转换
泛型的主要目的就是:指定当前容器要持有什么类型的对象,接着让编译器去检查类型,此时就是把类型作为参数传递,需要什么类型就传入什么类型
格式: <数据类型>
注意: 泛型只能支持引用数据类型
泛型的擦除:
类型擦除是Java编译器在编译泛型代码时的一个步骤。在编译过程中,编译器会将泛型信息从代码中擦除,并在需要的地方插入类型转换和类型检查代码。这样,运行时的字节码不包含任何泛型类型信息,只包含原始类型和必要的类型转换。
ArrayList<Integer> arrayList = new ArrayList<>();
例如在创建集合时,当数据真正的添加到集合里边的时候,集合还是会把它们当作Object类处理,只不过往外获取时会进行相应的强制类型转换
泛型类
当一个类中,某个变量的类型不确定,就可以定义带有泛型的类
格式:
修饰符 class 类名 <类型>{
}
class MyArray <E>{ private Object[] arr = new Object[10]; public void set(int index,E value){ arr[index] = value; } public E get(int index){ return (E) arr[index];// } } public class Demo1 { public static void main(String[] args) { MyArray<Integer> myArray = new MyArray<>(); //已经确定好类型了 //myArray.set(0,"Str"); 自动类型检查,要与上面的类型一致 myArray.set(0,1); int i = myArray.get(0); System.out.println(i); //创建String类型 MyArray<String> myArray2 = new MyArray<>(); myArray2.set(0,"hello"); String str = myArray2.get(0); System.out.println(str); } }
上面的MyArray就是一个泛型类,通过使用泛型,就对传入的数据类型进行了约束,同时,也实现了可以传入不同的类型参数
泛型方法
当一个类中只有一个方法中要用到不确定的类型,就只需要把这个方法定义为泛型方法即可
格式:
修饰符 <类型> 返回值类型 方法名(类型 变量名){
}
class ListUtil{ public void show(){ System.out.println("其他方法···"); } public static <E> void addAll(ArrayList<E> list,E e1,E e2,E e3){ list.add(e1); list.add(e2); list.add(e3); } public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); addAll(list,"a","b","c"); System.out.println(list); ArrayList<Integer> list2 = new ArrayList<>(); addAll(list2,1,2,3); System.out.println(list2); } }
泛型接口
格式:
修饰符 interface 接口名<类型>{
}
例如Java中的List接口就是一个泛型接口:
泛型接口的使用方法:
1.实现类给出具体类型
2.实现类延续泛型,创建对象时再确定类型
泛型的继承和通配符
泛型不具备继承性,但数据具备继承性
什么意思呢
首先定义了两个具有继承关系的类,method方法里边所限定的类型是Fu 类型,它的子类型所创建的对象并不能使用该方法,如果想要子类型也能使用,就需要把方法定义为泛型方法,但是如果是其他类型也可以使用,怎么去限定只有这种具有继承关系的类才能使用
这时就可以使用通配符来实现
通配符:?
也表示不确定类型,但是可以限定类型,
? extend E: 表示可以传递E 或 E所有的子类类型
? super E: 表示可以传递E 或 E 所有的父类类型
泛型的上界
上面介绍的通过extend进行类型限制就是指定了泛型的上界,下面还有一种复杂的示例
例如:
写一个泛型类,定义一个方法,可以求数组的最大值
这时候就需要用到compareTo方法,就要实现comparable接口
public class Alg<E extends Comparable<E>> { //对泛型进行了限制,必须实现Comparable接口的类型才能传入 public E findMax(E[] array){ E max = array[0]; for(int i = 0;i < array.length;i++){ if(max.compareTo(array[i]) < 0){ max = array[i]; } } return max; } public static void main(String[] args) { Integer[] arr = {1,2,3,4,5}; Alg<Integer> alg = new Alg<>(); int a = alg.findMax(arr); System.out.println(a); //5 } }
比如再定义一个Person类,因为它没有实现Comparable接口,所以泛型里边不能传入Student