泛型呢,一般在编程语言里是可以加快程序运行速度的,但是在Java中呢,并没有什么用,并不会加速程序的运行,那不是多余的吗?当然不是,存在即合理,下面开始说一说Java的泛型。
Java中呢,泛型的好处就是:1.编译期进行类型检查 ; 2.类型不确定时使用。
那怎么用呢,或是为什么是编译期的类型检查呢?接下来举
/**示例:泛型类和通配符*/
// 形式 类型参数
//这个T 也可以换成别的字母,但是一般有个规范
Type T
Element E
Key K
Value V
class Point<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 TestPoint {
public static void main(String[] args) {
//这里你定义成Integer类 对应上边所有,即传入参数也要用int的
Point<Integer> p1 = new Point<>();
p1.setX(11);//int -> Integer->Object
p1.setY(22);
System.out.println(p1.getX()+","+p1.getY());
Point<Double> p2 = new Point<>();
p2.setX(11.1);// double -> Double ->Object
p2.setY(22.2);
System.out.println(p2.getX()+","+p2.getY());
Point<String> p3 = new Point<>();
p3.setX("11.1");//String -> Object
p3.setY("22.2");
System.out.println(p3.getX()+","+p3.getY());
// 类型《具体的类型参数》 参数化类型
// Point<Integer> p4 = new Point<Integer>();
//类型推断 菱形语法
Point<Object> p4 = new Point<>();
p4.setX(11);
p4.setY(22);
Integer x = (Integer)p4.getX();
Integer y = (Integer)p4.getY();
System.out.println(x + "," + y);
//P1 ->Integer p2->Double p3->String p4 ->Object
TestPoint t = new TestPoint();
t.show2(p4);
System.out.println("----------------------------------");
Class c1 = p1.getClass();
Class c2 = p2.getClass();
System.out.println(c1);
System.out.println(c2);
System.out.println(c1 == c2);
//---------------------------------------------------------
}
public void show3(Point<String> ps,Point<? extends Object> po) {
po = ps;
}
//任意 ? 通配符 这里 后边再详细说通配符
public void show(Point<?> p) {
System.out.println(p.getX() + ":" + p.getY());
}
//只限制 为数值
public void show1(Point<? extends Number> p) {
System.out.println(p.getX() + ":" + p.getY());
}
public void show2(Point<? super Number> p) {
System.out.println(p.getX() + ":" + p.getY());
}
}
接口能用吗?
/**示例:类型参数上限*/
interface Info1{}
interface Info2{}
class Base{}
class Sub extends Base implements Info1,Info2{}
//可以指定多个上限 ,可以是 类 也可以是接口
class Point1<T extends Base & Info1 & Info2>{
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 TestPoint1 {
public static void main(String[] args) {
Point1<Sub> p1 = new Point1<>();
}
}
再来看一个:
class Point2<T>{
private T x;
private T y;
//泛型构造器 如果前边不加声明 就会报错
<E> Point2(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 TestPoint2 {
public static void main(String[] args) {
//类型推断 根据参数推断
Point2<String> p = new Point2<>(11);
Point2<String> p1 = new <Integer>Point2<String>(22);
}
}
泛型方法定义:
class Demo{
//泛型方法定义
public <T> void f(T t) {
System.out.println(t);
}
public <T extends Object> T ff(T t) {
//调用了泛型方法
//类型推断
f("hello");
//显示指定具体的类型时 必须 用对象调用
this.<String>f("hellotom");
return t;
}
}
public class TestPoint3 {
public static void main(String[] args) {
Demo d = new Demo();
//类型推断,根据参数推断
d.f("hello");
d.f(22);
//
d.<String>f("hellotom");
d.<Double>f(22.2);
}
}
那么 子类能继承父类的泛型吗?也是不能的,泛型只存在于编译期,在运行阶段就擦除了,所以 如下,方法重载的问题也是要注意的。
class Demo1{
//能方法重载吗?????不能
public void f(Point<String> p) {}//Point t
// public void f(Point<Integer> p) {}
<T> void f(T t) {}// Object t
<T extends Number> void f(T t) {}// Number t
<T extends Base & Info1> void f(T t) {}// Base t
<T extends Info1 & Info2> void f(T t) {}// Info1 t
}
class Parent{
//父类擦除后 与 子类参数相同
public void f(Point<String> p) {}// Point p
}
class Child extends Parent{
@Override
public void f(Point p) {}
}
public class TestPoint4 {
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
泛型接口,
//泛型接口
interface IA<T>{
void af(T t);
}
//1.能确定类型
class IAImpl1 implements IA<String>{
@Override
public void af(String t) {
System.out.println(t);
}
}
//2.不能确定接口类型
class IAImpl2<T> implements IA<T>{
@Override
public void af(T t) {
System.out.println(t);
}
}
public class TestPoint5 {
public static void main(String[] args) {
IAImpl2<Integer> ia = new IAImpl2<>();
ia.af(34);
IAImpl2<String> ia1 = new IAImpl2<>();
ia1.af("abc");
}
}
其实觉得泛型只是起到了检查作用,需要注意的就是 泛型的特性,就是会擦除,字节码文件中是没有泛型的存在的,这也是为什么用到了泛型,却并没有加速程序的运行,另外就是 通配符和 类型参数的区别。
类型参数 与 通配符的区别:
1.类型参数 可以表示一种类型;
通配符不能 表示一种类型;
2.类型参数 只能指定 上限;
通配符 可以指定上限 也可以指定下限;
3.类型参数 可以指定 多个上限;
通配符只能指定一个上限。
擦除的规则:
1.参数化类型
Point<String>
擦除后 为 原生类型
Point
2.类型参数
1)无界类型参数,擦除后 为 Object
class Point<T>
<T> void f(T t){}
2)有一个上限
用上限替换
3)有多个上限
用第一个上限来替换
这是比较重要的,另外就是两种写法要注意。