Java泛型详解

this.second = second;

}

public T getFisrt(){

return first;

}

public T getSecond(T newValue) {

first = newValue;

}

}

  • Java中使用T来表示任意类型,E来表示集合中的元素,K和V分别表示键和值的类型。

  • 泛型类可以有多个类型参数

注意:①泛型的类型参数只能是类类型,不能是基本属性类型;②不能对确切的泛型类型使用instanceof操作。如下面的操作是非法的,编译时会出错。if(ex_num instanceof Generic<Number>){ }

4.2 泛型接口


泛型接口与泛型类的定义及使用基本相同。泛型接口常被用在各种类的生成器(专门负责创建对象的类)中,一个生成器一般只定义一个next方法,用于产生新的对象。可以看一个例子:

//定义一个泛型接口

public interface Generator {

public T next();

}

当实现泛型接口的类,未传入泛型实参时:

/**

  • 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中

  • 即:class FruitGenerator implements Generator{

  • 如果不声明泛型,如:class FruitGenerator implements Generator,编译器会报错:“Unknown class”

*/

class Generator implements Generator{

@Override

public T next() {

return null;

}

}

当实现泛型接口的类,传入泛型实参时:

/**

  • 传入泛型实参时:

  • 定义一个生成器实现这个接口,虽然只创建了一个泛型接口Generator

  • 但是可以为T传入无数个实参,形成无数种类型的Generator接口。

  • 在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型

  • 即:Generator,public T next();中的的T都要替换成传入 的String类型。

*/

public class Generator implements Generator {

private String[] fruits = new String[]{“Apple”, “Banana”, “Pear”};

@Override

public String next() {

Random rand = new Random();

return fruits[rand.nextInt(3)];

}

}

4.3 泛型方法


上面介绍了泛型类,还可以定义带有参数类型的方法,即泛型方法。定义泛型方法,只需要将泛型参数列表置于方法返回值之前,就像下面:

/**

  • 1)泛型参数 可以理解为声明此方法为泛型方法

  • 2)只有声明了的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。

  • 3)泛型的数量也可以为任意多个
    

*/

public class GenericMethods {

public void f(T x) {

System.out.println(x.getClass.getName());

}

public static void main(sring[] args) {

GenericMethods gm = new GenericMethods();

gm.f(“”);//java.lang.String

gm.f(1);//java.lang.Integer

gm.f(1.0);//java.lang.Double

gm.f(‘a’);//java.lang.Character

gm.f(gm);//GenericMethods

}

}

  • 使用泛型类时必须在创建对象时指定类型参数的值,而使用泛型方法时通常不必指明类型参数 。因为编译器会我们找出具体的类型,可以向调用普通方法一样调用泛型方法。

  • 泛型方法使得方法能独立于类而产生变化,无论何时,如果你能做到,你就该尽量使用泛型方法。也就是说,如果使用泛型方法可以取代将整个类泛型化,那么就应该使用泛型方法.

4.3.1 泛型方法与可变参数

泛型方法与可变参数列表能够很好的共存:

public class GenericTest {

//使用可变参数的泛型方法

public static void printMsg(T… args) {

for (T t :args) {

System.out.print(t + " ");

}

}

public static void main(String[] args) {

GenericTest.printMsg(“111”, 222, ‘A’, 100.000);

}

}

4.3.2 静态方法与泛型

静态方法有一种情况需要注意一下,那就是在类中的静态方法使用泛型:静态方法不能使用泛型类的类型参数;如果静态方法要使用泛型的话,必须将静态方法也定义成泛型方法 。

public class StaticGenerator {

/**

  • 如果在类中定义使用泛型的静态方法,需要添加额外的泛型声明(将这个方法定义成泛型方法)

  • 即使静态方法要使用泛型类中已经声明过的泛型也不可以。

  • 如:public static void show(T t){…},此时编译器会提示错误信息:

“StaticGenerator cannot be refrenced from static context”

*/

public static void show(T t){

}

}

4.3.3 泛型方法总结

  • 泛型方法可以在普通类中定义,也可以在泛型类中定义

  • 无论何时,如果你能做到,你就该尽量使用泛型方法。也就是说,如果使用泛型方法可以取代将整个类泛型化,那么就应该使用泛型方法.

  • static修饰的方法无法访问泛型类的类型参数。所以如果static方法需要使用泛型能力,就必须使其成为泛型方法。

  • 在泛型方法中出现了泛型的结构,泛型参数与类的泛型参数没任何关系。即泛型方法所属的类是不是泛型类都没关系。

4.4 泛型注意点


在这里插入图片描述

4.5 类型通配符


  • 泛型在继承方面的体现:类A是类B的父类,但是G <A>G<B>二者不具备子父类关系,二者是并列关系【补充:类A是类B的父类,A<G>B<G> 的父类】。因此需要一个在逻辑上可以用来表示同时是G <A>G<B>的父类的一个引用类型,由此,类型通配符应运而生。

  • 类型通配符一般是使用 ? 代替具体的类型实参,G <A>G<B>二者的共同父类是G<?>

@Test

public void test(){

List list1 = null;

List list2 = null;

List<?> list = null;

list = list1;

list = list2;

//编译通过

// print(list1);

// print(list2);

List list3 = new ArrayList<>();

list3.add(“AA”);

list3.add(“BB”);

list3.add(“CC”);

list = list3;

//添加(写入):对于List<?>就不能向其内部添加数据。(除了添加null之外)

// list.add(“DD”);错误

// list.add(‘?’);错误

list.add(null);

//获取(读取):允许读取数据,读取的数据类型为Object。

Object o = list.get(0);

System.out.println(o);

}

public void print(List<?> list){

Iterator<?> iterator = list.iterator();

while(iterator.hasNext()){

Object obj = iterator.next();

System.out.println(obj);

}

}

  • 涉及通配符的集合的数据的写入和读取:

  • 添加(写入):对于List<?>不能向其内部添加数据。(除了添加null之外)

  • 获取(读取):允许读取数据,读取的数据类型为Object。

有限制的通配符

  • 类型通配符下限 :? extends A

  • G<? extends A> 可以作为G<A>G<B>的父类,其中B是A的子类

  • 类型通配符上限:? super A

  • G<? super A> 可以作为G<A>G<B>的父类,其中B是A的父类

**类比数学中的区间:

?相当于(-∞,+∞);? extends A——(-∞,A];? super A——[A,+∞)**

*/

@Test

public void test2(){

List<? extends Person> list1 = null;

List<? super Person> list2 = null;

List list3 = new ArrayList<>();

List list4 = new ArrayList<>();

List list5 = new ArrayList<>();

list1 = list3;

list1 = list4;

// list1 = list5;编译错误

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

本文从基础到高级再到实战,由浅入深,把MySQL讲的清清楚楚,明明白白,这应该是我目前为止看到过最好的有关MySQL的学习笔记了,我相信如果你把这份笔记认真看完后,无论是工作中碰到的问题还是被面试官问到的问题都能迎刃而解!

MySQL50道高频面试题整理:

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
你有帮助,可以扫码获取!!(备注Java获取)**

img

总结

本文从基础到高级再到实战,由浅入深,把MySQL讲的清清楚楚,明明白白,这应该是我目前为止看到过最好的有关MySQL的学习笔记了,我相信如果你把这份笔记认真看完后,无论是工作中碰到的问题还是被面试官问到的问题都能迎刃而解!

MySQL50道高频面试题整理:

[外链图片转存中…(img-F9oMu5JE-1713167586003)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 22
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java泛型Java 5引入的新特性,可以提高代码的可读性和安全性,降低代码的耦合度。泛型是将类型参数化,实现代码的通用性。 一、泛型的基本语法 在声明类、接口、方法时可以使用泛型泛型的声明方式为在类名、接口名、方法名后面加上尖括号<>,括号中可以声明一个或多个类型参数,多个类型参数之间用逗号隔开。例如: ```java public class GenericClass<T> { private T data; public T getData() { return data; } public void setData(T data) { this.data = data; } } public interface GenericInterface<T> { T getData(); void setData(T data); } public <T> void genericMethod(T data) { System.out.println(data); } ``` 其中,`GenericClass`是一个泛型类,`GenericInterface`是一个泛型接口,`genericMethod`是一个泛型方法。在这些声明中,`<T>`就是类型参数,可以用任何字母代替。 二、泛型的使用 1. 泛型类的使用 在使用泛型类时,需要在类名后面加上尖括号<>,并在括号中指定具体的类型参数。例如: ```java GenericClass<String> gc = new GenericClass<>(); gc.setData("Hello World"); String data = gc.getData(); ``` 在这个例子中,`GenericClass`被声明为一个泛型类,`<String>`指定了具体的类型参数,即`data`字段的类型为`String`,`gc`对象被创建时没有指定类型参数,因为编译器可以根据上下文自动推断出类型参数为`String`。 2. 泛型接口的使用 在使用泛型接口时,也需要在接口名后面加上尖括号<>,并在括号中指定具体的类型参数。例如: ```java GenericInterface<String> gi = new GenericInterface<String>() { private String data; @Override public String getData() { return data; } @Override public void setData(String data) { this.data = data; } }; gi.setData("Hello World"); String data = gi.getData(); ``` 在这个例子中,`GenericInterface`被声明为一个泛型接口,`<String>`指定了具体的类型参数,匿名内部类实现了该接口,并使用`String`作为类型参数。 3. 泛型方法的使用 在使用泛型方法时,需要在方法名前面加上尖括号<>,并在括号中指定具体的类型参数。例如: ```java genericMethod("Hello World"); ``` 在这个例子中,`genericMethod`被声明为一个泛型方法,`<T>`指定了类型参数,`T data`表示一个类型为`T`的参数,调用时可以传入任何类型的参数。 三、泛型的通配符 有时候,我们不知道泛型的具体类型,可以使用通配符`?`。通配符可以作为类型参数出现在方法的参数类型或返回类型中,但不能用于声明泛型类或泛型接口。例如: ```java public void printList(List<?> list) { for (Object obj : list) { System.out.print(obj + " "); } } ``` 在这个例子中,`printList`方法的参数类型为`List<?>`,表示可以接受任何类型的`List`,无论是`List<String>`还是`List<Integer>`都可以。在方法内部,使用`Object`类型来遍历`List`中的元素。 四、泛型的继承 泛型类和泛型接口可以继承或实现其他泛型类或泛型接口,可以使用子类或实现类的类型参数来替换父类或接口的类型参数。例如: ```java public class SubGenericClass<T> extends GenericClass<T> {} public class SubGenericInterface<T> implements GenericInterface<T> { private T data; @Override public T getData() { return data; } @Override public void setData(T data) { this.data = data; } } ``` 在这个例子中,`SubGenericClass`继承了`GenericClass`,并使用了相同的类型参数`T`,`SubGenericInterface`实现了`GenericInterface`,也使用了相同的类型参数`T`。 五、泛型的限定 有时候,我们需要对泛型的类型参数进行限定,使其只能是某个类或接口的子类或实现类。可以使用`extends`关键字来限定类型参数的上限,或使用`super`关键字来限定类型参数的下限。例如: ```java public class GenericClass<T extends Number> { private T data; public T getData() { return data; } public void setData(T data) { this.data = data; } } public interface GenericInterface<T extends Comparable<T>> { T getData(); void setData(T data); } ``` 在这个例子中,`GenericClass`的类型参数`T`被限定为`Number`的子类,`GenericInterface`的类型参数`T`被限定为实现了`Comparable`接口的类。 六、泛型的擦除 在Java中,泛型信息只存在于代码编译阶段,在编译后的字节码中会被擦除。在运行时,无法获取泛型的具体类型。例如: ```java public void genericMethod(List<String> list) { System.out.println(list.getClass()); } ``` 在这个例子中,`list`的类型为`List<String>`,但是在运行时,`getClass`返回的类型为`java.util.ArrayList`,因为泛型信息已经被擦除了。 七、泛型的类型推断 在Java 7中,引入了钻石操作符<>,可以使用它来省略类型参数的声明。例如: ```java List<String> list = new ArrayList<>(); ``` 在这个例子中,`ArrayList`的类型参数可以被编译器自动推断为`String`。 八、总结 Java泛型是一个强大的特性,可以提高代码的可读性和安全性,降低代码的耦合度。在使用泛型时,需要注意它的基本语法、使用方法、通配符、继承、限定、擦除和类型推断等问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值