Java拾贝第九天——泛型
Java拾贝不建议作为0基础学习,都是本人想到什么写什么
如果一个类中,不想限定一个属性的数据类型,或某个方法的返回值和传参。
可以在类声明时通过一个标识来表示。
这样只需要在实例化类的时候声明具体的数据类型即可,这就是泛型
也可以理解为广泛的数据类型,即不限制的数据类型
泛型类
泛型作用于类上就是泛型类。
声明一个泛型类
class 类名<泛型标识符>{//拥有标识符的类就是泛型类
访问修饰符 泛型标识符 变量名;
访问修饰符 泛型标识符 方法名(){};
....
}
栗子:
public class Test9 {
public static void main(String[] args) {
MyF<String> f = new MyF<String>();
//外部指定数据类型 第二个<>中的String可以省略
f.setName("泛型");
}
}
class MyF<T> {//泛型类
private T name;//属性不定义具体类型,使用泛型替代数据类型
public MyF() {
}
public MyF(T name) {//构造方法也可也使用泛型
this.name = name;
}
public T getName() {//返回类型使用泛型
return name;
}
public void setName(T name) {//传参使用泛型
this.name = name;
}
}
上门的MyF类就是泛型的具体体现。其调用了"<T>"形式,泛型表示具体类型是由外部实例化MyF类时指定的。
<>中可以是任意的大写字母,<A>、<B>都可以。这里采用T仅仅是取type的开头而已。
泛型类在被初始化时指定类型
基本类型是无法指定的,只能指定引用类型
栗子:
MyF<int> f = new MyF<>();//错错错
传入的类型与泛型不一致。
栗子:
public class Test9 {
public static void main(String[] args) {
MyF<Integer> f = new MyF<>();
f.setName("传入String类型");//编译错误 初始化时指定的是Integer类型
}
}
class MyF<T> {
private T name;
public MyF() {
}
public MyF(T name) {
this.name = name;
}
public T getName() {
return name;
}
public void setName(T name) {
this.name = name;
}
}
传入的类型可以是某个类或其子类
栗子:
public class Test9 {
public static void main(String[] args) {
Point<Son> point = new Point<>();
//Point<Dad> point = new Point<>();一样没问题的
}
}
class Dad{
}
class Son extends Dad{
}
class Point<T>{
private T name;
public Point() {
}
public Point(T name) {
this.name = name;
}
public T getName() {
return name;
}
public void setName(T name) {
this.name = name;
}
}
静态属性不能使用泛型
栗子:
class Point<T>{
static T t;//错错错
因为静态处于全局内存区,JVM对静态的初始化会在类实例化之前。
此时使用泛型会导致JVM初始化全局内存不成功。因为泛型是不确定的数据类型
多个泛型
栗子:
public class Test9 {
public static void main(String[] args) {
Point<String, Integer> point = new Point<>("小明",18);
//外部指定属性name数据类型为String,属性age数据类型为Integer
}
}
class Point<T,K>{//任意字母都行
private T name;
private K age;
public Point() {
}
public Point(T name, K age) {
this.name = name;
this.age = age;
}
public T getName() {
return name;
}
public void setName(T name) {
this.name = name;
}
public K getAge() {
return age;
}
public void setAge(K age) {
this.age = age;
}
}
泛型擦除
即外部不指定具体类型。
栗子:
public class Test9 {
public static void main(String[] args) {
Point point = new Point();
point.setName("小明");
}
}
class Point<T>{
private T name;
public Point() {
}
public Point(T name) {
this.name = name;
}
public T getName() {
return name;
}
public void setName(T name) {
this.name = name;
}
}
上述栗子会出现不安全警告信息。
虽然不指定泛型类型后编译出现了警告,但是并不影响程序运行。
这是因为Java在这种情况(不指定泛型类型)下默认采用Object进行接收。也称泛型擦除
泛型接口
泛型作用于接口上就是泛型接口。
interface 接口名<泛型标识符>{//泛型接口
}
栗子:
interface Cat<T>{
void getCat(T t);
}
泛型接口在被继承,或被实现时需指定类型
栗子:
interface Cat<T>{
void getCat(T t);
}
interface Dog extends Cat<String>{//被继承
}
class tc implements Cat<String>{//被实现
@Override
public void getCat(String s) {
System.out.println("不定义会泛型擦除,记得确定数据类型");
}
}
泛型方法
泛型作用于方法上就是泛型方法。
栗子:
public <T> void opq(T temp1) {
System.out.println(temp1);
}
可以使用泛型类中的泛型标识符,或泛型方法中的泛型标识符。
栗子:
class Gen<T>{
public <K,V> void tell(T t,K k){//可以使用泛型类中的泛型标识符,或泛型方法中的泛型标识符。
System.out.println("泛型类中的泛型方法");
}
}
泛型方法不光可以在泛型类中,还可以在普通类中:
栗子:
class Pen{
public <K,V> void tell(K k){//泛型不一定要全部使用
System.out.println("普通类中的泛型方法");
}
}
普通方法也可也使用泛型:
栗子:
class Gen<T>{
public <K> void tell(T t){//泛型方法
System.out.println("泛型类中的泛型方法");
}
public void say(T t){//只是传参使用泛型而已 这不是泛型方法!!!
System.out.println("普通方法使用泛型");
}
}
补充
泛型方法中一个泛型可以当多个数据类型使用。
栗子:
public class Test10 {
public static void main(String[] args) {
opq("张三", 18);
}
public static <T> void opq(T temp1, T temp2) {
System.out.println(temp1 + " + " + temp2);
}
}
程序运行结果:
张三 + 18
静态方法的返回值不能使用泛型!
栗子:
public static <T> opq(T temp1) {//错错错
System.out.println(temp1);
}