泛型:
参数化数据类型
作用于
类,方法,构造器,接口
泛型类:
在声明类的后面加上类型参数
好处
语法
类名<类型参数>
类型参数可以是一个也可以是多个,多个用逗号分隔
用一个大写字母表示,一般用 T-type E—element K—key V—value
原生类型:
类型后没有 指定具体的类型参数,这样的类型
叫 原生类型。
泛型的通配符
?是无界通配符,可以匹配任意的引用类型
? extends 上限类型 及其上限类型的子类型
super 可以匹配下限类和下限类的父类
注意
类型参数可以指定上限(上界),
1.但是只能指定上界
2.还可以指定多个上限
3.上限可以是类也可以是接口
4.上限既有类又有接口,要先继承类,后实现接口;类在前,接口在后
类型参数和通配符的区别
1.类型参数 只能指定上限,通配符可以指定上限和下限
2.类型参数可以指定多个上限,通配符只能指定一个
3.类型参数可以作为一个类型,通配符不能表示为一种类型
问题,String是Object的子类,那么Point 是否是Point的子类型
答:不是,参数化类型不能继承
//用通配符解决
public void show(Point<String> ps,Point<? extends Object> po){
po = ps;
}
问题:会生成几个泛型类
一个。泛型只是起到在编译时期进行类型检查的作用,并不会生成多个字节码文件
//验证
Point3<Integer> p1 = new Point3();
System.out.println(p1.getClass());
Point3<String> p2 = new Point3<>();
System.out.println(p2.getClass());
//运行结果:
class day21.Point3
class day21.Point3
泛型构造
package day21;
class Point4<T>{
private T x;
private T y;
//泛型构造器
<E>Point4(E e){
System.out.println(e);
}
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public T getY() {
return y;
}
public void setY(T y) {
this.y = y;
}
}
public class Ex4 {
public static void main(String[] args) {
//类型推断:根据串的参数的类型确定E是String
Point4<Integer> p4 = new Point4<Integer>("Hello");
Point4<Integer> p6 = new Point4<>("hello");
//显示指定构造器是String类型,此时不能用菱形语法
Point4<Integer> p5 = new <String>Point4<Integer>("Hello");
}
}
泛型方法
package day21;
//普通类
class Point5{
//泛型方法
public <T> void f(T t){
System.out.println(t);
}
//<一>
//public <T extends Number> T ff (T t){
//<二>
public <T extends Number> T ff (T t){
//自动推断
f("hello");
//如果显示指定的化,要用对象去调用:this.<String>f("abc");this.<String>f("abc");都是指定了对象
this.<String>f("abc");
return t;
}
}
public class Ex5 {
public static void main(String[] args) {
Point5 p5 = new Point5();
//类型推断:根据参数的类型推断
p5.f("Hello");
p5.f(11);
//<一>
//显示指定类型参数
//p5.<String>f("abc");
//<二>
p5.<Double>f(11.0);
}
}
类型擦除
1.参数化类型擦除后为原生类型
point -> point
2.类型参数:使用上界替换
(1)无界类型参数
Point ——> Object
会用Object替换
(2)指定了一个上限的,用此上限类型来替换
Point ——> Base
(3)指定了多个上限的,用第一个上限替换
Point
重写方法
package day21;
interface IA1{
}
interface IB1{
}
class Base1 {
public void f(Point6<String> p) throws Exception {}
}
class Sub1 extends Base1 {
//重写了
@Override
public void f(Point6<String> p) throws Exception{
// TODO Auto-generated method stub
super.f(p);
}
}
class Point6<T>{
private T x;
private T y;
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public T getY() {
return y;
}
public void setY(T y) {
this.y = y;
}
}
public class Ex6 {
public void f(Point6<String> p){}//Point6
public <T> void f(T p){};//Object
public <T extends Base1> void f(T p){} //Base1
public <T extends IA1 & IB1> void f(T p){} //IA1
public static void main(String[] args) {
}
}
父类参数擦除后和子类相同
异常范围不能比父类大
泛型接口
package day21;
//泛型接口
interface Info <T>{
void af(T t);
}
//实现类一:实现接口的时候就指定好用什么类型来替换
class InfoImpl1 implements Info<String>{
@Override
public void af(String t) {
// TODO Auto-generated method stub
}
}
//实现类二:确定不了类型,等应用再定义:InfoImpl2<String> info = new InfoImpl2<String> ();
class InfoImpl2<T> implements Info<T>{
@Override
public void af(T t) {
// TODO Auto-generated method stub
}
}
public class Ex7 {
public static void main(String[] args) {
InfoImpl2<String> info = new InfoImpl2<String> ();
}
}
比较器 TestCompare
自然排序:按照 Comparable接口的方法CompareTo排序
问题:不想按照现有排序方法进行排序,应该怎么解决
实现Comparator 函数式接口
Comparator Exercise4 和 Comparable的区别 Exercise3
1.Comparable是默认的自然排序方式,Comparator 是我们指定的一种排序方式
2.Comparable的比较代码写在要比较对象的类型的内部,Comparator写在比较类型代码的外部
3.Comparable只能指定一种 默认排序方式,Comparator可以定义多种排序方式
枚举
- 底层就是class类
- 已经继承了一个类Enum,不能再继承其他的类
- 对于一个非抽象的枚举类型,默认是final
- 构造器是private的
- 不能创建对象,在枚举代码的第一行处
- 所有的枚举对象都是 public static final的
- 当枚举的类中定义了抽象方法,那么每个对象的匿名内部类方式都必须实现这个抽象方法,并且这个枚举类为abstract的
语法:
enum Color{
枚举成员;
方法();
构造();
}
实例代码
package day21;
import java.util.Scanner;
interface InfoNew{
void af();//抽象方法
}
//可以实现接口
enum Color implements InfoNew{
//在这里调用构造器
RED(1,"红色"){
@Override
public void af() {
System.out.println("红色的实现接口");
}
@Override
void f() {
System.out.println("红色的实现抽象类");
}
},GREEN(2,"绿色"){
@Override
public void af() {
System.out.println("绿色的实现接口");
}
@Override
void f() {
System.out.println("绿色的实现抽象类");
}
}, BLUE(3,"蓝色"){
@Override
public void af() {
System.out.println("蓝色的实现接口");
}
@Override
void f() {
System.out.println("绿色的实现抽象类");
}
};
//成员变量
private int no;
private String name;
//构造器 是private的,在这里写没必要
private Color(int no, String name) {
this.no = no;
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//自定义方法
public void show(){
System.out.println("show");
}
//重写
@Override
public String toString() {
return no + name;
}
//定义抽象方法
abstract void f();
}
public class Ex8 {
public static void main(String[] args) {
//重写了Stringto
System.out.println(Color.RED);
//定义了构造器
System.out.println(Color.RED.getName() +","+ Color.RED.getNo());
System.out.println(Color.BLUE.getName() +","+ Color.BLUE.getNo());
System.out.println(Color.GREEN.getName() +","+ Color.GREEN.getNo());
//定义成员变量
/* Color.RED.no = 11;
Color.RED.name = "红色";
System.out.println(Color.RED.name);
System.out.println(Color.RED.no);
*/
//私有成员变量
Color.RED.setNo(22);
Color.RED.setName("红色");
System.out.println(Color.RED.getName() +"," +Color.RED.getNo());
//每一个枚举成员都可以调用自定义方法
Color.BLUE.show();
//-----------------------------------
/* System.out.println(Color.RED);
System.out.println(Color.GREEN);
System.out.println(Color.BLUE);
//遍历
for (Color c : Color.values()){
System.out.println(c.name());
//获得枚举类型的编号
System.out.println(c.ordinal());
}
//-----------Switch------------------
Scanner input = new Scanner(System.in);
System.out.println("输入颜色");
String str = input.next();
//字符串转换为枚举Color类型
Color c = Color.valueOf(str);
switch (c){
case RED:
System.out.println("是红色");
break;
case GREEN:
System.out.println("是绿色");
break;
case BLUE:
System.out.println("是蓝色");
break;
}*/
}
}