Java基础语法泛型
程序员文章站
2022-03-25 15:00:43
/* * 泛型的使用形式有2种: * 1、泛型类\泛型接口 * 2、泛型方法 * * 一、泛型类/接口 * 1、语法格式: * 【修饰符】 class 类名<泛型形参列表>{ * } * 【修饰符】 interface 接口名<泛型形参列表>{ * } * * 例如: * public interface Collection 就是泛型形参列表 * public class ArrayList
/*
* 泛型的使用形式有2种:
* 1、泛型类\泛型接口
* 2、泛型方法
*
* 一、泛型类/接口
* 1、语法格式:
* 【修饰符】 class 类名<泛型形参列表>{
* }
* 【修饰符】 interface 接口名<泛型形参列表>{
* }
*
* 例如:
* public interface Collection<E> <E>就是泛型形参列表
* public class ArrayList<E> <E>就是泛型形参列表
* public class HashMap<K,V> <K,V>就是泛型形参列表
* 我们看到在声明类或接口时,<E>,<K,V>,<T>,<U>....都是泛型的形参列表
* 这些E,K,V,T等代表的是某种元素的类型
*
* ArrayList<String> list = new ArrayList<String>();
* 此时:<String>泛型的实参列表
*
* //存储本组学员的姓名(key)和它的年龄(value)
* HashMap<String,Integer> map = new HashMap<String,Integer>();
* 此时:<String,Integer>是泛型的实参列表
*
* 2、要求
* 泛型实参必须是一个引用数据类型,不能是基本数据类型
*
* 3、如何为泛型类、泛型接口指定泛型实参
* (1)创建泛型类的对象时
* Student<String> chinese = new Student<String>("张三","优秀");
* (2)继承泛型类、泛型接口时可以指定泛型实参
* class ChineseStudent extends Student<String>
* (3)实现泛型接口时,可以指定泛型实参
* class Employee implements Comparable<Employee>
*/
public class TestGenericClass {
@Test
public void test1(){
// ArrayList<int> list = new ArrayList<int>();//错误
ArrayList<Integer> list = new ArrayList<Integer>();//对
}
@Test
public void test2(){
//语文老师
Student<String> chinese = new Student<String>("张三","优秀");
//数学老师
Student<Double> math = new Student<Double>("张三",89.5);
//英语老师
Student<Character> english = new Student<Character>("张三",'A');
}
@Test
public void test3(){
//语文老师
ChineseStudent c = new ChineseStudent("张三","优秀");
}
}
/*
* 自定义一个泛型类:
* 定义一个“特殊”的学生类,学生类包含两个属性:姓名,成绩
* 此时成绩的情况很复杂:
* 语文老师在表示学生时:成绩登记为:优秀、良好、及格、不及格
* 数学老师在表示学生时:成绩登记为:89.5 ....
* 英语老师在表示学生时:成绩登记为:A,B,C,D...
*
* <T>:泛型形参
* T在这个Student当做就是score的类型,凡是需要表示score的类型的地方都用T
*/
class Student<T>{
private String name;
private T score;
public Student(String name, T score) {
super();
this.name = name;
this.score = score;
}
public Student() {
super();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public T getScore() {
return score;
}
public void setScore(T score) {
this.score = score;
}
@Override
public String toString() {
return "Student [name=" + name + ", score=" + score + "]";
}
}
//语文老师
class ChineseStudent extends Student<String>{
public ChineseStudent() {
super();
}
public ChineseStudent(String name, String score) {
super(name, score);
}
}
//接口:java.lang.Comparable<T>
class Employee implements Comparable<Employee>{
private int id;
private String name;
public Employee(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + "]";
}
@Override
public int compareTo(Employee o) {
return this.id - o.id;
}
}
/*
* 补充:
* 4、泛型类或泛型接口上的<泛型形参>这个类型可以用在哪些地方?
* (1)可以用于属性、方法的数据形参、局部变量等的类型
* (2)不能用于静态成员上
*
* 5、泛型类或泛型接口的泛型形参,可以设定上限
* <T extends 上限>
* T的类型实参只能上限本身或上限的子类
*
* <T extends 上限1 & 上限2 & 。。。。>
* 如果多个上限,都要满足
*
* 6、 泛型的形参一般代表什么的类型?
* ArrayList<E>:这个E代表集合的元素的类型
* Map<K,V>:这个K代表key的类型,V代表的value的类型
* Comparable<T>:这个T代表,要与当前对象比较的另一个对象的类型
* Student<T>:这个T代表成绩的类型
*
* 7、如果在使用泛型类或泛型接口的时候,没有指定泛型实参,会怎么样?
* 泛型被擦除,泛型被擦除后,泛型形参被解析为什么类型呢?
* 被解析为泛型形参的第一个上限的类型。
* (1)如果没有指定泛型形参的上限,就按照Object处理
* (2)如果指定泛型形参的上限,就按照上限处理,如果有多个上限,多个上限用&连接,按照最左边的第一个上限处理
*/
public class TestGenericClass2 {
@Test
public void test02(){
ArrayList list = new ArrayList();
list.add("1");//泛型擦除,按照Object处理
XueSheng x = new XueSheng("张三", 89);//XueSheng(String, Number)
AClass a = new AClass();
a.test(1);//按照Nubmer处理
}
@Test
public void test01(){
// XueSheng<String> x = new XueSheng<String>("张三","优秀");//错误的,因为String不是Number或Number的子类
XueSheng<Double> x1 = new XueSheng<Double>("张三",89.5);
XueSheng<Integer> x2 = new XueSheng<Integer>("张三",89);
XueSheng<Long> x3 = new XueSheng<Long>("张三",89L);
}
}
//T的上限,
//T的类型实参要求,同时是Number的子类,还要实现Comparable和Serializable接口
class AClass<T extends Number & Comparable & Serializable>{
public void test(T t){
}
}
/*
* 自定义一个泛型类:
* 定义一个“特殊”的学生类,学生类包含两个属性:姓名,成绩
* 此时成绩的情况很复杂:
* 语文老师在表示学生时:成绩登记为:87
* 数学老师在表示学生时:成绩登记为:89.5 ....
*
* <T>:泛型形参
* T在这个XueSheng当做就是score的类型,凡是需要表示score的类型的地方都用T
*
* 此时想要限定这个T必须是一个数字,不能是字符串等其他类型
*/
class XueSheng<T extends Number>{
private String name;
private T score;
public XueSheng(String name, T score) {
super();
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public T getScore() {
return score;
}
public void setScore(T score) {
this.score = score;
}
@Override
public String toString() {
return "XueSheng [name=" + name + ", score=" + score + "]";
}
}
class MyClass<T>{
private T t;//用于当做属性的数据类型
// private static T t2;
public MyClass(T t) {//用于当做方法的数据形参的类型
super();
this.t = t;
}
//可以用于返回值的类型
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public void test(){
T t;//局部变量的类型
}
/* public static T getT2() {
return t2;
}
public static void setT2(T t2) {
MyClass.t2 = t2;
}*/
}
泛型方法:
/*
* 二、泛型方法
* 1、什么情况需要声明泛型方法?
* (1)如果某个静态方法想要使用泛型,需要单独设计
* 例如:java.util.Arrays数组工具类
* public static <T> List<T> asList(T... a)
* T...是可变参数
*
* (2)如果泛型类或泛型接口上的泛型形参不适用于某一个方法(可以是静态的,也可以是非静态),那么这个方法,可以单独设计泛型
* 例如:java.util.Collection<E>
* public abstract <T> T[] toArray(T[] a)
*
* 2、泛型方法的语法格式
* 【修饰符】 <泛型形参列表> 返回值类型 方法名(【数据形参列表】)
*
* 3、泛型方法的<泛型形参列表>这个类型就用于当前方法的形参类型、返回值类型、局部变量,和其他方法无关
*
* 4、泛型方法的类型形参,什么时候指定类型实参
* 当你调用这个方法时,编译器会根据方法的实参的类型,来确定泛型的类型实参的具体类型
*
* 5、泛型方法的<泛型形参列表>中的类型也可以指定上限
* <T extends 上限>
* T的类型实参只能上限本身或上限的子类
*
* <T extends 上限1 & 上限2 & 。。。。>
* 如果多个上限,都要满足
*/
public class TestGenericMethod {
public <T extends Number> T test(T t){
//...
return t;
}
@Test
public void test03(){
Integer num = test(1);
Double d = test(1.0);
// test("hello");//错的,因为String不符合Number的上限
}
@Test
public void test02(){
Collection<String> c = new ArrayList<String>();
c.add("张三");
c.add("李四");
String[] arr = new String[2];
String[] array = c.toArray(arr);//根据arr的数组类型,来确定返回值的T[]的类型
Object[] all = new Object[2];
Object[] array2 = c.toArray(all);//根据all的数组类型,来确定返回值的T[]的类型
}
@Test
public void test01(){
List<Integer> list1 = Arrays.asList(1,2,3,4,5);//根据1,2,3,4,5可以确定T是Integer类型
List<String> list2 = Arrays.asList("hello","java");//根据"hello","java"确定T是String类型
}
}
泛型的通配符
/*
* 通配符:wildcard
* 通配符:?
* 1、<?>:代表可以是任意类型
* 2、<? extends 上限>:?代表是上限或上限的子类
* 3、<? super 下限>:?代表的是下限或下限的父类
*
* 看java.util.Collections:集合工具类
* (1)public static boolean disjoint(Collection<?> c1, Collection<?> c2)看c1和c2是否有交集,如果没有交集返回true
*/
public class TestWildcards {
@Test
public void test05(){
Collection<String> src = new ArrayList<String>();
src.add("hello");
src.add("world");
Collection<Integer> dest = new ArrayList<Integer>();
dest.add(1);
dest.add(2);
// copy(src,dest);//把src中的"hello"、"world"添加的dest中,有问题
Collection<Object> dest2 = new ArrayList<Object>();
copy(src, dest2);//把src中的"hello"、"world"添加的dest2中,没问题 此时T是String,?是Object
}
/*
* 举例:
* 想要声明一个方法,可以把一个Collection集合src中的所有元素,添加到另一个Collection集合dest中
*/
public <T> void copy(Collection<T> src, Collection<? super T> dest){
for (T object : src) {
dest.add(object);
}
}
@Test
public void test04(){
ArrayList<String> list1 = new ArrayList<String>();
// printGraphic(list1);//错误的因为String不满足<? extends Graphic>
ArrayList<Circle> list2 = new ArrayList<Circle>();
printGraphic(list2);//因为Circle满足<? extends Graphic>
}
/*
* 举例:
* 想要声明一个方法,遍历一个里面装着图形对象的集合
*/
public void printGraphic(Collection<? extends Graphic> c){
for (Graphic graphic : c) {
System.out.println(graphic);
}
}
@Test
public void test03(){
Collection<String> c1 = new ArrayList<String>();
c1.add("hello");
Collection<Integer> c2 = new ArrayList<Integer>();
c2.add(1);
System.out.println(Collections.disjoint(c1, c2));
}
@Test
public void test01(){
List<Integer> list = Arrays.asList(1,2,3,4);
print(list);
}
/*
* 声明一个方法:这个方法可以用于遍历所有的Collection系列的集合
* 此时因为Collection是一个泛型接口,Collection<E>
* 如果此时不指定<E>的具体类型,会报警告,(1)方式一,抑制警告(2)方式二:用?来代表任意类型
* 因为此时不知道要被遍历的集合的元素类型是什么
*/
public void print(Collection<?> c){
for (Object object : c) {
System.out.println(object);
}
}
//以前我们说Object可以接收任意类型对象,但是不代表Collection<Object>可以接收任意泛型实参的集合
//Collection<Object>这么写,只能接收Collection<Object>,List<Object>...,即泛型实参必须是<Object>
/* public void print(Collection<Object> c){
for (Object object : c) {
System.out.println(object);
}
}*/
@Test
public void test2(){
Object str = new String();//是多态
// ArrayList<Object> list = new ArrayList<String>();//错误的,不是多态
ArrayList<Object> list1 = new ArrayList<Object>();
ArrayList<String> list2 = new ArrayList<String>();
}
}
//图形类
class Graphic{
//...
}
//圆类
class Circle extends Graphic{
//...
}
//矩形类
class Rectangle extends Graphic{
//...
}
集合的工具类Collections
/*
* java.util.Collections工具类:
* (1)public static <T> boolean addAll(Collection<? super T> c,T... elements):把elements这些元素添加到c这个集合中
* (2)public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key):在list集合中找出key,用二分查找法
* 此时要求list集合是有大小顺序
* <? extends Comparable<? super T>>:list集合中的元素必须是实现Comparable接口,?可以是T或T的父类,这个父类实现现Comparable接口也可以
*
* (3)public static <T> int binarySearch(List<? extends T> list,T key,Comparator<? super T> c)
* 此时要求list集合是有大小顺序的,按照你指定的Comparator进行比较大小
* <? extends T>:是T或T的子类,说明list中存的元素是T类型的对象或T类型的子类对象
* <? super T>:这个比较器是为T或T的父类设计的比较器也可以
*
* (4)public static <T> void copy(List<? super T> dest,List<? extends T> src):把src的元素复制到dest
* src中存的是T或T的子类的对象
* dest要求元素类型是T或T的父类类型
*
* (5)public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
* <T extends Object & Comparable<? super T>>是max方法的泛型形参列表,泛型形参T,设定了上限,说明T必须继承Object并且要实现Comparable接口
* max方法用于在coll集合中找出最大的元素,要求这个元素可比较大小,所以 要求T元素实现Comparable接口
*
* <? extends T>:coll集合中存的是T或T的子类的对象
*
* (6)public static <T> T max(Collection<? extends T> coll,Comparator<? super T> comp)
* 如果coll中的元素不支持自然比较大小,那么用comp这个定制比较器比较元素的大小
*
* (7)public static void reverse(List<?> list):可以反转任意的List集合元素
*
* (8)public static void shuffle(List<?> list):类似于洗牌
*
* (9)public static <T> Set<T> singleton(T o):返回一个只有一个元素的Set集合
*
* (10)public static <T extends Comparable<? super T>> void sort(List<T> list):用于给List集合排序
* <T extends Comparable<? super T>>要求集合中的元素实现Comparable接口
*
* (11)public static <T> void sort(List<T> list, Comparator<? super T> c):可以按照定制比较器排序
*
* (12)public static void swap(List<?> list,int i,int j):交换list中[i]与[j]位置的元素,List<?>代表集合的元素可以是任意类型
*
* (13)public static <T> List<T> synchronizedList(List<T> list):可以把一个线程不安全的list集合变成一个线程安全的list集合
* 。。。
* (14)public static <T> List<T> unmodifiableList(List<? extends T> list):把list集合变成一个不可修改的集合,只读的集合
*
*/
public class TestCollections {
@Test
public void test5(){
List<Integer> list = Arrays.asList(1,2,3,4);
System.out.println(list);
//说明list是一个只读的集合
// list.add(5);//UnsupportedOperationException
System.out.println(list.getClass());//class java.util.Arrays$ArrayList不是java.util.ArrayList
}
@Test
public void test4(){
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
System.out.println(list);
Collections.shuffle(list);
System.out.println(list);
}
@Test
public void test3(){
ArrayList<SubCircle> list = new ArrayList<SubCircle>();
list.add(new SubCircle(1.2));
list.add(new SubCircle(2.2));
list.add(new SubCircle(3.2));
//T是Circle类型
//因为Graphic是Circle的父类,<? super T>
//SubCircle是Circle的子类,满足<? extends T>
Collections.binarySearch(list, new Circle(2.2), new Comparator<Graphic>(){
@Override
public int compare(Graphic o1, Graphic o2) {
if(o1.getArea() > o2.getArea()){
return 1;
}else if(o1.getArea() < o2.getArea()){
return -1;
}
return 0;
}
});
}
@Test
public void test2(){
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(5);
list.add(9);
//此时的T是Integer
//list的<Integer>,这个Integer
int index = Collections.binarySearch(list, 4);
}
@Test
public void test1(){
//元素是1,2,3,4
ArrayList<Integer> list = new ArrayList<Integer>();
ArrayList<String> list2 = new ArrayList<String>();
ArrayList<Object> list3 = new ArrayList<Object>();
ArrayList<Number> list4 = new ArrayList<Number>();
//此时T是Integer类型,
//<? super T>:可以是Integer或它的父类
Collections.addAll(list, 1,2,3,4);
//此时T是Integer类型,
//因为String不满足<? super T>
// Collections.addAll(list2, 1,2,3,4);
//此时T是Integer类型,
//Object满足<? super T>
Collections.addAll(list3, 1,2,3,4);
//此时T是Integer类型,
//Nubmer满足<? super T>
Collections.addAll(list4, 1,2,3,4);
}
}
abstract class Graphic{
public abstract double getArea();
}
class Circle extends Graphic{
private double radius;
public Circle(double radius) {
super();
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
@Override
public String toString() {
return "Circle [radius=" + radius + "]";
}
}
class SubCircle extends Circle{
public SubCircle(double radius) {
super(radius);
}
}
本文地址:https://blog.csdn.net/kewu8971/article/details/107672227