Java面向对象编程----面向对象(四)

124 阅读5分钟

接口

类似与抽象类,但比抽象类要更严格、更抽象它不能有任何的方法实现(体现了多态和高内聚低偶合的设计思想)。

接口的成员(字段 + 方法)默认都是 public 的,并且不允许定义为 private 或者 protected。
接口的字段默认都是 static 和 final 的。
接口多继承,可以继承多个接口,对java单继承机制的补充。
抽象类可以不实现接口方法,普通类必须要实现。
通过接口扩展子类功能

public class InterfaceDemo extends AbstractExample{
    public void getInfo(){
        System.out.println("必需实现抽象类方法");
    }
    public void print(){
        System.out.println("必需实现接口方法");
    }
    public static void main(String[] args) {
        InterfaceDemo In = new InterfaceDemo();
        In.out();
    }

}

interface InterfaceExample  {
    // static final可省略
    public static final int X_VALUE = 1;
    // abstract 可省略
    public abstract void print();
}

abstract class AbstractExample implements InterfaceExample{
    public abstract void getInfo();
    // 抽象类可以不实现接口方法
    public void out(){
        System.out.println(InterfaceExample.X_VALUE);
    }
}

接口设计不一定是完美的,当实现该接口的子类较多时,接口新增方法就需要每个子类都实现该方法。在jdk1.8之前,为解决这个问题,是通过在接口与子类之间加上一个过渡抽象类来实现的。

jdk1.8后,接口支持了普通方法,但是需要加default声明,同时这个功能属于接口定义加强,接口设计时不考虑。
除此之外,接口还支持了static方法,可以通过接口直接调用.

泛型

通过泛型对参数进行约束,在使用时才确定具体参数类型,防止转换成具体的目标类型出现java.lang.ClassCastException异常
Java 语言中的泛型实现方法称为类型擦除,基于这种方法实现的泛型被称为伪泛型, 简单的来说就是在编译时将代码还原成没有泛型的样子,而实际上是直接转化成字节码文件了。
适用于多种数据类型执行相同的代码(代码复用)

静态变量是被泛型类的所有实例所共享的。对于声明为 MyClass的类,访问其中的静态变量的方法仍然是 MyClass.myStaticVar 。不管是通过new MyClass还是 new MyClass创建的对象,都是共享一个静态变量。 泛型无法处理异常类,因为到运行时由于类型擦除的原因无法区分两个异常的具体类型

private static <T extends Number> double add (T a, T b){
    System.out.println("a + b = " + (a.doubleValue() + b.doubleValue()));
    return  a.doubleValue() + b.doubleValue();
}

泛型的基本使用

泛型类

  • 简单类型
class Point<T>{         // 此处可以随便写标识符号,T是type的简称  
    private T var ;     // var的类型由T指定,即:由外部指定  
    public T getVar(){  // 返回值的类型由外部决定  
        return var ;  
    }  
    public void setVar(T var){  // 设置的类型也由外部决定  
        this.var = var ;  
    }  
}  
public class GenericsDemo{  
    public static void main(String args[]){  
        Point<String> p = new Point<String>() ;     // 里面的var类型为String类型  
        p.setVar("it") ;                            // 设置字符串  
        System.out.println(p.getVar().length()) ;   // 取得字符串的长度  
    }  
}
  • 多元泛型
class Notepad<K,V>{       // 此处指定了两个泛型类型  
    private K key ;     // 此变量的类型由外部决定  
    private V value ;   // 此变量的类型由外部决定  
    public K getKey(){  
        return this.key ;  
    }  
    public V getValue(){  
        return this.value ;  
    }  
    public void setKey(K key){  
        this.key = key ;  
    }  
    public void setValue(V value){  
        this.value = value ;  
    }  
} 
public class GenericsDemo{  
    public static void main(String args[]){  
        Notepad<String,Integer> t = null ;        // 定义两个泛型类型的对象  
        t = new Notepad<String,Integer>() ;       // 里面的key为String,value为Integer  
        t.setKey("汤姆") ;        // 设置第一个内容  
        t.setValue(20) ;            // 设置第二个内容  
        System.out.print("姓名;" + t.getKey()) ;      // 取得信息  
        System.out.print(",年龄;" + t.getValue()) ;       // 取得信息  
  
    }  
}

泛型接口

interface  Info <T>{ // 在接口上定义泛型
    public T getInfo();// 定义抽象方法,抽象方法的返回值就是泛型类型
}
class InfoImpl<T> implements Info<T>{// 定义泛型接口的子类
    private T var ;             // 定义属性
    public InfoImpl(T var){     // 通过构造方法设置属性内容
        this.setVar(var) ;
    }
    public void setVar(T var){
        this.var = var ;
    }
    @Override
    public T getInfo() {
        return this.var;
    }
}
public class GenericDemo {
    public static void main(String[] args) {
        Info<String> info = new InfoImpl<String>("test");
        System.out.println("内容:" + info.getInfo()) ;
    }
}

泛型方法

泛型类,是在实例化类的时候指明泛型的具体类型;泛型方法,是在调用方法的时候指明泛型的具体类型\

class的作用就是指明泛型的具体类型,而class类型的变量c,可以用来创建泛型类的对象。

class Food {}
class Fruit extends Food {}
class Apple extends Fruit {}
class Banana extends Fruit{}

class GenericTest {
    public void testExtends(List<? extends Fruit> list){
        //报错,extends为上界通配符,只能取值,不能放.
        //因为Fruit的子类不只有Apple还有Banana,这里不能确定具体的泛型到底是Apple还是Banana,所以放入任何一种类型都会报错
        //list.add(new Apple());

        //可以正常获取
        Fruit fruit = list.get(1);
    }

    public void testSuper(List<? super Fruit> list){
        //super为下界通配符,可以存放元素,但是也只能存放当前类或者子类的实例,以当前的例子来讲,
        //无法确定Fruit的父类是否只有Food一个(Object是超级父类)
        //因此放入Food的实例编译不通过
        list.add(new Apple());
//        list.add(new Food());
        Object object = list.get(1);
    }
}
  • 定义泛型方法 image.png

  • 调用泛型方法

image.png

  • 限定通配符和非限定通配符

限定通配符对类型进⾏限制,泛型中有两种限定通配符:
表示类型的上界,格式为:<? extends T>,即类型必须为 T类型或者T子类
表示 类型的下界,格式为:<? super T>,即类型必须为T类型或者T的父类

泛型类型必须⽤限定内的类型来进⾏初始化,否则会导致编译错误。
⾮限定通配符表⽰可以⽤任意泛型类型来替代,类型为<T>。

  • 上下界限定符extends和super
是指“上界通配符”,即泛型中的类必须为当前类的子类或当前类. \ ,泛型中的类必须为当前类或者其父类。