版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_1018944104/article/details/82838339
目录
一、泛型类
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(外部比较器)
- 外部指定的一个比较方式。
- 代码写在比较的元素的类外的。
八、递归
递归定义:允许方法调用自身的一种方式。
实现原则:
- 方法调用自身
- 有出口