JavaSE之泛型

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_1018944104/article/details/82838339

目录

一、泛型类

1.什么是泛型?

2.泛型的作用?

3.泛型类的定义

4.泛型类的应用

5.类型参数

二、泛型通配符及上限、下限

1.泛型通配符及上限、下限

2.如何使用泛型通配符?

3.类型参数与通配符的区别

三、泛型构造器

1.语法规则

2.使用方式

四、泛型方法

五、泛型擦除

1.什么是泛型擦除?

2.泛型擦除的原则

3.泛型擦除对方法重载、重写的影响

六、泛型接口

1.声明方式

2.实现方式

七、比较器

1.Comparable 接口

2.Comparator 接口

3.Comparable 与Comparator的区别:

八、递归


一、泛型类

1.什么是泛型?

  • 泛型就是参数化类型,即 类型<实际类型参数>

2.泛型的作用?

  • 在编译期进行类型检查;
  • 定义类时,若类型不确定可以使用泛型。

3.泛型类的定义

class 类名<泛型类型标识> {
    访问修饰符 <泛型类型> 属性;
    访问修饰符 <泛型类型> 方法(){}
    访问修饰符 <泛型类型> 方法(泛型类型 参数){}
}
class 类名<类型参数> {}

4.泛型类的应用

类名<具体类> 对象名 = new 类名<>();

说明:

  • 菱形语法:即JDK7.0版本,系统自动进行类型推断,即根据声明时的实际类型参数推断构造器的实际类型参数。
  • 原生类型:参数化类型后面没有指定实际类型参数,这样的类型称为原生类型。每个参数化类型都有一个原生类型。
  • 不同实际类型参数是否产生多个字节码文件?不会。在生成字节码文件时会发生类型擦除,换句话说,类型参数是在编译期用来检查类型的,跟运行期没有关系。

5.类型参数

  • 定义时:形式类型参数
  • 应用时:实际类型参数(必须是引用类型)
  • 用大写字母表示形式参数,可以定义多个形式类型参数,在菱形符号中,用逗号隔开

二、泛型通配符及上限、下限

1.泛型通配符及上限、下限

  • ?:无界通配符,可以匹配任意类型
  • <? extends E>:接收E或者E的子类型
  • <? super E>:接收E或者E的父类型

2.如何使用泛型通配符?

//兼容任意类型
public void showPoint(Point<?> p){
    System.out.println(p.getX() + ":" + p.getY());
}

//数字Byte,Short,Integer,Long,Float,Double -> 父类 Number
//兼容Number及其子类
public void showPoint(Point<? extends Number> p){
    System.out.println(p.getX() + ":" + p.getY());
} 

public void check(Point<String> s, Point<? extends Object> o){
    //String是Object的子类
    o = s;
}

3.类型参数与通配符的区别

  • 类型参数可以表示一种类型,即泛型类型,而通配符不能表示为一种类型,仅用作类型匹配。
  • 类型参数只能指定上限,而通配符能执行上限和下限。
  • 类型参数可以指定多个上限,通配符不能。
class Parent{}
class Child extends Parent{}
interface IA{}
interface IB{}

//<T extends Parent & IA & IB> 表示T必须既继承Parent类又实现IA和IB接口
class Point<T extends Parent & IA & IB>{
    private T x;
    private T y;
}

三、泛型构造器

1.语法规则

class Point<T>{
    private T x;
    private T y;
    //泛型构造器的定义
    public <E> Point(E e){
        System.out.println(e);
    }
}

2.使用方式

public class Test{
    public static void main(){
        //自动类型推断:用泛型类的实际类型参数自动推断出构造器实际类型参数
        Point<String> p = new Point<>(11);
        //显示的指定了构造的实际类型参数:这种情况下,泛型类的自动类型推断无法生效,也许显示指定
        Point<String> p1 = new <Integer>Point<String>(22);
    }
}

四、泛型方法

语法格式及使用方式,如下:

//例1:
class Demo{
    //泛型方法
    public <T> void f(T t){
        System.out.println(t);
    }
}
public class TestPoint{
    public static void main(String[] args){
        Demo demo = new Demo();
        //自动类型推断
        demo.f("hello");
        demo.f(123);
        //显示指定泛型方法的实际类型参数
        demo.<Double>f(22.2);
    }
}

//例2:
class Demo{
    //泛型方法
    public <T> void f(T t){
        System.out.println(t);
    }
    public <T> T ff(T t){
        //类型推断
        f(22);
        //显示指定参数:必须用对象调用
        this.<Double>f(22.2);
        return t;
    }
}

五、泛型擦除

1.什么是泛型擦除?

源代码被编译成字节码文件时,会将代码中的类型参数删除掉,代码中使用类型参数的地方按照擦除原则进行替换。

2.泛型擦除的原则

参数化类型

  • 参数化类型擦除后会用原生类型进行替换,比如Point<String> p -> Point p;

类型参数

  • 无界类型参数,擦除后用Object替换,比如class Point<T>{} -> class Point<Object>{ 类体部分都用Object替换 }
  • 有一个上限的类型参数,擦除后用上限来替换。比如<T extends A> -> A
  • 有多个上限的类型参数,擦除后用第一个上限类替换,比如<T extends A & B> -> A

3.泛型擦除对方法重载、重写的影响

//注意:以下这些同名方法,构成重载
class Demo{
    //参数化类型擦除后变为:public void f(Point p){}
    public void f(Point<Integer> p){}
    //无界类型参擦除后变为:public void f(Objetc t){}
    public <T> void f(T t){}
    //有一个上限的类型参数擦除后变为:public void f(Demo t){}
    public <T extends Demo> void f(T t){}
    //有多个上限的类型参数擦除后变为:public void f(IX t){}
    public <T extends IX & IY> void f(T t){}
    //有多个上限的类型参数擦除后变为:public void f(IY t){}
    public <T extends IY & IX> void f(T t){}
}

六、泛型接口

1.声明方式

interface Info<T>{
	void f(T t);
}

2.实现方式

//实现方式一:在实现接口时确定类型
class Demo1 implements Info<String>{
	@Override
	public void f(String t) {
		System.out.println(t);
	}
}
//实现方式二:实现时无法确定
class Demo2<T> implements Info<T>{
	@Override
	public void f(T t) {
		System.out.println(t);
	}
}
public class TestInfo {
	public static void main(String[] args) {
		Demo2<String> d = new Demo2<>();
	}
}

七、比较器

1.Comparable 接口

import java.util.Arrays;
class Stu implements Comparable<Stu>{
	private int score;
	public int getScore() {
		return score;
	}
	public void setScore(int score) {
		this.score = score;
	}
	public Stu(int score) {
		super();
		this.score = score;
	}
	public Stu() {
		super();
	}
	@Override
	public String toString() {
		return "Stu[score = " + score + "]";
	}
	@Override
	public int compareTo(Stu o) {
		//降序
		/*if (this.score > o.score) {
			return -1;
		} else if (this.score < o.score) {
			return 1;
		}
		return 0;*/
		return o.score - this.score;//降序
//		return this.score - o.score;//升序
/*		//升序
		if (this.score > o.score) {
			return 1;
		} else if (this.score < o.score) {
			return -1;
		}
		return 0;
*/	}
}
public class TestScore {
	public static void main(String[] args) {
//		Stu stu1 = new Stu(89);
//		Stu stu2 = new Stu(99);
//		Stu stu3 = new Stu(95);
		int [] i = new int[]{1,2,4};
		Stu[] stus = new Stu[]{new Stu(89), new Stu(99), new Stu(95)};
//		Stu[] stus = {stu1, stu2, stu3};
		Arrays.sort(stus);
		for (Stu stu : stus) {
			System.out.println(stu);
		}
	}
}

2.Comparator 接口

import java.util.Arrays;
import java.util.Comparator;
class Stu implements Comparable<Stu>{
	private int score;
	public int getScore() {
		return score;
	}
	public void setScore(int score) {
		this.score = score;
	}
	public Stu(int score) {
		super();
		this.score = score;
	}
	public Stu() {
		super();
	}
	@Override
	public String toString() {
		return "Stu[score = " + score + "]";
	}
	@Override
	public int compareTo(Stu o) {
		//降序
		/*if (this.score > o.score) {
			return -1;
		} else if (this.score < o.score) {
			return 1;
		}
		return 0;*/
		return o.score - this.score;//降序
//		return this.score - o.score;//升序
/*		//升序
		if (this.score > o.score) {
			return 1;
		} else if (this.score < o.score) {
			return -1;
		}
		return 0;
*/	}
}

public class TestScore {
	public static void main(String[] args) {
		Stu[] stus = new Stu[]{new Stu(89), new Stu(99), new Stu(95)};
		//自然升序排序
		Arrays.sort(stus);//升序排序
		//用户可以自定义比较器
		/*Arrays.sort(stus, new Comparator<Stu>() {
			@Override
			public int compare(Stu o1, Stu o2) {
				return o2.getScore() - o1.getScore();
			}
		});*///降序排序
		Arrays.sort(stus, (o1,o2)->o2.getScore() - o1.getScore());//Lambda表达式
		for (Stu stu : stus) {
			System.out.println(stu);
		}
	}
}

3.Comparable 与Comparator的区别:

Comparable(内部比较器)

  • 使用元素默认的自身的比较方式;
  • 代码是写在元素的类中的。

Comparator(外部比较器)

  • 外部指定的一个比较方式。
  • 代码写在比较的元素的类外的。

八、递归

递归定义:允许方法调用自身的一种方式。

实现原则:

  • 方法调用自身
  • 有出口

猜你喜欢

转载自blog.csdn.net/qq_1018944104/article/details/82838339