包装类
什么是包装类
在讲基本数据类型的时候,有提到过包装类。
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
我们知道:基本数据类型并不是对象,没有对象所具有的方法和属性。为了让基本数据类型能像对象一样使用,Java提供了包装类。
用途:
1、作为对象使用:提供了一些对基本类型的数据进行操作的方法。将字符串转整数、求数据类型的范围等等。
2、在泛型中的应用:对于什么泛型等下再讲。泛型只能使用对象类型,不能使用基本数据类型,这是需要包装类。
3、集合框架:集合(用于存储和操作一组对象的框架,如:ArrayList等)只能存储对象,不能存储基本数据类型,这是需要包装类。
装箱和拆箱
代码案例:
1、
public static void main(String[] args) {
int a = 200;
Integer integer = Integer.valueOf(a);//手动装箱
System.out.println(integer);
Integer integer1 = new Integer(a);//手动装箱
System.out.println(integer1);
Integer integer2 = a;//自动装箱
System.out.println(integer1);
System.out.println("=============");
int j = integer.intValue();//手动拆箱
System.out.println(j);
int jj = integer;//自动拆箱
System.out.println(jj);
}
2、
public static void test() {
Integer a = 100;
Integer b = 100;
System.out.println(a == b);//输出:true
Integer c = 200;
Integer d = 200;
System.out.println(c == d);//输出:false
}
代码解释:
1、
装箱操作:就是将基本数据类型转换为对应的包装类对象的过程。
拆箱操作:就是把包装类对象转换为对应的基本数据类型的过程。
手动装箱:调用包装类的构造方法或者valueOf()
方法。
手动拆箱:调用包装类的xxxValue()方法,其中xxx代表的是基本数据类型,如intValue()
、doubleValue()
等。
对于编译器来说,会自动的装箱和拆箱。但要注意的是:在自动拆箱时,如果包装类对象为null,会抛出NullPointerException异常。
2、
为啥第二个输出false?
我们知道这是完成了自定装箱,调用了valueOf()
方法。我们来看一下valueOf()
方法。
这时候我们发现当i在一个范围时,会指向同一个Integer对象(来自缓存)。此时使用==比较时,比较的是对象的引用,他们引用的是同一个对象,输出true。
当不再范围时,会各自创建一个新的Integer对象。此时使用==比较时,比较的是对象的引用,他们引用的不是同一个对象,输出false。
通过这个缓存,找到了其范围。-128 ~ 127
泛型
什么是泛型
泛型:就是适用于许多许多类型。从代码上来说,就是实现了对类型的参数化。
种类
1、泛型类
代码案例:
public class Box<T> {
private T content;
public T getContent() {
return content;
}
public void setContent(T content) {
this.content = content;
}
public Box(T content) {
this.content = content;
}
}
public static void test1() {
Box<Integer> box1 = new Box<>();
//Box<Integer> box1 = new Box<Integer>();
box1.setContent(10);
System.out.println(box1.getContent());
System.out.println("============");
Box<String> box2 = new Box<>();
box2.setContent("World");
box2.setContent(10);//报错
System.out.println(box2.getContent());
}
public static void test2() {
Box box = new Box(10);//不会报错,但有警告
Box box2 = new Box("Hello");//不会报错,但有警告
}
代码解释:
1、对于test1()中的new Box<>()
的<>中类型可写可不写
2、当你指定了类型时(也就是<>中的类型),存放类型不匹配时,编译器会报错。
3、对于test2()中,直接没有<>明确指出类型,此时编译器会自动判断。但最好不要这样写代码。
泛型的上界
当我们相对传入的类型进行约束,可以规定泛型的边界。
语法:
class 泛型类名称<T extends 类型边界> {
}
代码案例:
1、
public class MyArray<T extends Number> {
private final Object[] array = new Object[10];
public T getPos(int pos) {
return (T)this.array[pos];
}
public void setVal(int pos,T val) {
this.array[pos] =val;
}
}
public class Test {
public static void main(String[] args) {
MyArray<Integer> myArray = new MyArray<>();
myArray.setVal(0,10);
System.out.println(myArray.getPos(0));
MyArray<Number> myArray1 = new MyArray<>();
MyArray<String> myArray2 = new MyArray<>();//报错
}
}
2、
class Max<T extends Comparable<T>> {
public T findMax(T[] array) {
T max = array[0];
for (int i = 1; i < array.length; i++) {
if(max.compareTo(array[i]) < 0) {
max = array[i];
}
}
return max;
}
}
public class Test {
public static void main(String[] args) {
Max<Integer> maxInteger = new Max<>();
Integer[] integers = {1,2,33,65,7};
Integer max = maxInteger.findMax(integers);
System.out.println(max);
}
}
代码解释:
1、class MyArray<T extends Number>
就规定了T的上界是Number类,此时T的类型只能是Number的子类或这本身。
2、泛型没有下界
3、没有指定类型边界T,可以视为T extends Object
4、代码案例二,实现了比较T类型数组中的最大值。在if语句中我们使用了Comparable接口的compareTo方法。(由于传入的T类型不都能用 < 或 > 简单的进行比较,会像下图一样报错)
2、泛型方法
代码案例:
1、
class Swap {
public static <T> void swap(T[] array, int i,int j) {
T temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
public class Test<T> {
private static<T> void printArray(T[] array) {
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]+" ");
}
System.out.println();
}
public T find(T[] array,int pos) {
return array[pos];
}
public static void main(String[] args) {
Integer[] intArray = {1,2,3,4,5};
Swap.swap(intArray,2,3);
printArray(intArray);
System.out.println("=====");
String[] stringArray = {"Hello","World"};
Swap.swap(stringArray,0,1);
printArray(stringArray);
System.out.println("=====");
Test<Integer> integerTest = new Test<>();
System.out.println(integerTest.find(intArray, 4));
}
}
2、
public class Test {
public static <T extends Comparable<T>> T findMax(T[] array) {
T max = array[0];
for (int i = 1; i < array.length; i++) {
if(max.compareTo(array[i]) < 0) {
max = array[i];
}
}
return max;
}
public static void main(String[] args) {
Integer[] integers = {1,2,33,65,7};
Integer max = findMax(integers);
System.out.println(max);
}
}
代码解释:
1、对于普通方法,new对象的时候,根据<>中的类型知道T的类型(例如:find()
)。而对于静态方法,由于是通过类名调用方法,此时编译器就不知道 T 到底是什么类型,这时候需要在static后面加上<T>
,编译器就会根据传入的参数来判断 T 是什么类型。(例如:swap()
和 printArray()
)
2、对于Swap类后面可加<T>可不加<T>
3、对刚才实现的找最大值方法改成静态方法并加入边界。
3、泛型接口
在学习接口的时候就有涉及到。Comparable接口就是一个泛型接口。
public interface Comparable<T> {
public int compareTo(T o);
}