Java中使用泛型和Objects类需要注意的几个地方
一、泛型
泛型,即“参数化类型”,将类型由原来的具体的类型参数化,可以让Java类、调用方法动态地改变类型。
1.泛型类型必须是引用类型
泛型本质是Object类,而int不是,Java中的泛型是通过编译时的类型擦除(去泛型化)来完成的,当泛型被类型擦除后都变成Object类型。但是Object类型不能指代像int,double这样的基本类型只能指代Integer,Double这样的引用类型。
所以使用泛型时不小心使用了int等基本数据类型会报错
public class Demo01 {
public static void main(String[] args) {
Person<int> p = new Person<>();
//int处报错:Syntax error, insert "Dimensions" to complete ReferenceType
//需要插入一个(类型)方向来完善引用类型
//将int改成相对应的包装类或Object类
p.setData(100);
System.out.println(p.getData());
System.out.println(p.toString());
}
}
class Person<T>{
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String toString() {
return "ClassName [data=" + data + "]";
}
}
2.通配符需要注意的地方
泛型使用?作为类型通配符,表示未知类型,可以匹配任何类型,当使用通配符时,带有通配符的对象,对泛型类中的参数为泛型的方法起到了限制,不能再使用。?代表的类型参数是未知,所以无法添加元素,也就是无法使用set方法,但是由于Object是所有类的父类,所以可以将元素定义为Object类并取出来,可以使用get方法。
但是如果就是想使用通配符的情况下还想使用set方法,可以使用
Plate<? super Apple> p = new Plate<Apple>(a1);
即当下界为调用的类型的时候可以使用set方法,但是当上界为调用的类型时不能使用set方法。
Plate<? extends Apple> p = new Plate<Apple>(a1);
package until4_1topHalf;
public class Demo1 {
public static void main(String[] args) {
Apple a1 = new Apple(111);
Plate<? extends Fruit> p = new Plate<Apple>(a1);
//p.setData(a1);这条语句会报错
//The method setData(capture#1-of ?) in the type Person<capture#1-of ?> is not applicable for the arguments (int)
//类型Person中的方法setData(capture#1-of ?)不适用于参数(int)
System.out.println(p.getData());
System.out.println(p.toString());
}
}
interface Fruit{}
class Apple implements Fruit{
Object size;
public Apple(int size) {
super();
this.size = size;
}
public String toString() {
return "Apple [size=" + size + "]";
}
}
class Plate<T>{
T data;
public Plate(T data) {
super();
this.data = data;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String toString() {
return "Plate [data=" + data + "]";
}
}
/*输出为:
*Apple [size=111]
*Plate [data=Apple [size=111]]
*/
二、Objects
1.Object与Objects区别
Object是所有类的基类,位于java.lang包中,使用时不需要导入包
Objects的所有方法是static修饰的,可以通过类名直接访问;而Objects类本身又final修饰,不能被继承,说明是一个工具类,Objects位于java.until包中,使用时一定要导包才能使用。
2.Objects使用注意
Objects不能被构造 创建对象时报错:The constructor Objects() is not visible
调用Objects的方法参数基本上不能传入基本数据类型,除了三个判断范围的方法除外:
1.checkFromIndexSize(int fromIndex, int size, int length)
2.checkFromToIndex(int fromIndex, int toIndex, int length)
3.checkIndex(int index, int length)
这三个方法的参数都是int类型,同时可以将一个int类型强制转为Object类或Integer类也是能使用的,同时需要注意的是调用这三个方法返回结果为false时是直接返回异常的,同样结果为false时返回异常的方法有:
1.public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier):检查指定的对象引用是否为null ,true返回NullPointerException 类异常。
2.public static <T> T requireNonNull(T obj, String message) :检查指定的对象引用是否为null ,true返回NullPointerException 类异常。
import java.util.Objects;
public class Demo02 {
public static void main(String[] args) {
//Objects o = new Objects();
//报错:The constructor Objects() is not visible
Person p1 = new Person();
Person p2 = null;
int i1 = 80;
int i2 = 99;
Object i3 = (Object)i2;
Integer i4 = (Integer)i2;
System.out.println(Objects.checkIndex(8, 100));
System.out.println(p1.equals(p2));
//System.out.println(i2.equals(i1));
//参数为基本类型报错:Cannot invoke equals(int) on the primitive type int
/*判断子范围从fromIndex (第一个参数,范围包括)到fromIndex + size (参数二、不包括)
* 是范围界限内0 (包括)到length (参数三、不包括)。
* true返回参数1的值,false返回IndexOutOfBoundsException类异常
*/
System.out.println(Objects.checkFromIndexSize(5, 2, i2));
/*检查是否在子范围从参数一(包括)到参数二(不包括)
* 是范围界限内0 (包括)到length (参数三,不包括)
* 不包括同样返回异常
*/
System.out.println(Objects.checkFromToIndex(10, 99, i4));
/*检查index是否在0 (含)到length (不包括)范围内。
*不包括同样返回异常
*/
System.out.println(Objects.checkIndex(8, 100));
System.out.println(Objects.equals(p2,p1));
System.out.println(Objects.isNull(p2));
System.out.println(Objects.requireNonNull(p1));
}
}