java 抽象类与接口 学习笔记

抽象类与接口

一、抽象类

1. 抽象类基本定义

抽象类使用abstract class定义,并且其中的方法也可利用abstract定义若干个抽象方法,这样抽象类的子类必须再继承抽象类时强制全部覆写方法

import java.util.Date;

public class AbstractDemo {
    public static void main(String[] args) {
        Message msg = new DataMessage();
        msg.setType("信息类型");
        System.out.println(msg.getType());
        DataMessage datamsg = (DataMessage) msg;
        System.out.println(datamsg.getConnect());
    }
}
abstract class Message{
    private String type;
    public abstract String getConnect();

    public void setType(String type){
        this.type = type;
    }

    public String getType(){
        return this.type;
    }
}
class DataMessage extends Message{
    @Override
    public String getConnect(){
        return "数据库链接信息!";
    }
}

2. 抽象类相关说明

  1. 抽象类必须由子类继承,所以不允许使用final关键字定义抽象类或者抽象方法
  2. 抽象类中可以定义普通方法和成员属性,为了初始化成员属性, 还提供了构造方法。子类继承抽象类会默认调用父类的无参构造,如果没有提供无参构造,则子类必须通过super()形式调用指定参数的构造方法
public class AbstractDemo {
    public static void main(String[] args) {
        Message msg = new DataMessage("信息类型");
        System.out.println(msg.getType());
        DataMessage datamsg = (DataMessage) msg;
        System.out.println(datamsg.getConnect());
    }
}
abstract class Message{
    private String type;

    public Message(String type){
        this.type = type;
    }

    public abstract String getConnect();

    public void setType(String type){
        this.type = type;
    }

    public String getType(){
        return this.type;
    }
}
class DataMessage extends Message{
    public DataMessage(String type){
        super(type);
    }

    @Override
    public String getConnect(){
        return "数据库链接信息!";
    }
}
  1. 抽象类中允许没有抽象方法,即使没有抽象方法,也无法直接使用关键字new直接实例化抽象类
  2. 抽象类可以提供static方法,并且该类方法不受到抽象类实例化对象的限制
public class AbstractDemo {
    public static void main(String[] args) {
        Message msg = Message.getInstance();
        System.out.println(msg.getInfo());
    }
}
abstract class Message{
    public abstract String getInfo();
    public static Message getInstance(){// 静态方法
        System.out.println("打印抽象类中的静态方法");
        return new DataMessage();
    }
}
class DataMessage extends Message{
    @Override
    public String getInfo(){
        return "打印信息";
    }
}

3. 模板设计模式

public class AbstractDemo {
    public static void main(String[] args) {
        Action robotAction = new Robot();
        robotAction.command(Action.EAT);
    }
}
abstract class Action{
    public static final int EAT = 1;
    public static final int SLEEP = 5;
    public static final int WORK = 10;

    public abstract void eat();
    public abstract void sleep();
    public abstract void work();

    public void command(int code){
        switch (code) {
            case EAT:{
                this.eat();
                break;
            }
            case SLEEP:{
                this.sleep();
                break;
            }
            case WORK:{
                this.work();
                break;
            }
            case EAT+SLEEP+WORK:{
                this.eat();
                this.work();
                this.sleep();
                break;
            }
        }
    }
}

class Robot extends Action{
    @Override
    public void eat(){
        System.out.println("机器人要充电");
    }

    @Override
    public void sleep(){}

    @Override
    public void work(){
        System.out.println("机器人在干活");
    }
}

class pig extends Action{
    @Override
    public void eat(){
        System.out.println("杂食动物");
    }

    @Override
    public void sleep(){
        System.out.println("随地睡觉");
    }

    @Override
    public void work(){}
}

写一个抽象类,然后以此为模板,创建不同的子类对象,根据需要对方法进行覆写

二、包装类

1. 基础数据类型的包装

public class AbstractDemo {
    public static void main(String[] args) {
        Object obj = new Int(10);// 向上转型,将10包装在Int类中
        int x = ((Int) obj).IntValue();//向下转型为Int类,输出数字
        System.out.println(x*2);
    }
}
class Int{// 包装类
    private int data;
    public Int(int data){
        this.data = data;
    }

    public int IntValue(){
        return this.data;
    }
}

利用这种处理就可以用Object进行基本数据类型的接受,从而实现参数的统一化处理

Java设计了8个包装类,可分为了两种类型:

  1. 对象型包装类(Object直接子类):Boolean, Charachter
  2. 数值型包装类(Number直接子类):Byte,Short,Integer,Long,Float,Double
1. 装箱与拆箱

以Double和double为例实现转换

public class AbstractDemo {
    public static void main(String[] args) {
        Double obj = new Double(12.5);
        double num = obj.doubleValue();
        System.out.println(num*num);
    }
}

以Boolean和boolean为例实现转换

public class AbstractDemo {
    public static void main(String[] args) {
        Boolean obj = new Boolean(true);
        boolean flag = obj.booleanValue();
        System.out.println(flag);
    }
}

java在1.5之后实现了自动装箱功能,上面的写法就逐渐弃用了

public class AbstractDemo {
    public static void main(String[] args) {
        Integer obj = 10;
        int num = obj;
        obj++;
        System.out.println(num * obj);
    }
}

使用Object接收浮点数据

public class AbstractDemo {
    public static void main(String[] args) {
        Object obj = 12.5;// 利用Object接受一个浮点数,此时就是利用Object装箱
        double num = (Double) obj; // 想要拆箱,必须要向下转型为Double类型
        System.out.println(num*2);
    }
}

Integer自动装箱的数据比较问题

public class AbstractDemo {
    public static void main(String[] args) {
        Integer x = new Integer(10);
        Integer y = 10;
        Integer z = 10;
        System.out.println(x == y);//false
        System.out.println(x == z);//false
        System.out.println(z == y);//true
        System.out.println(x.equals(y));//true
    }
}
2. 装箱数据的==和euqals

装箱的数据,判断相等,如果数据范围在-128~127之间,会自动实现堆内存的引用,可以使用==判断

超出这个范围的数据,需要使用equals来实现相等比较

public class AbstractDemo {
    public static void main(String[] args) {
        Integer x = 100;
        Integer y = 100;
        Integer i = 130;
        Integer j = 130;
        System.out.println(x == y);// true
        System.out.println(i == j);// false
        System.out.println(i.equals(j)); // true
    }
}
3. 数据类型转换

java程序中的所有输入内容都会利用String类型表述,所以需要通过包装类实现各种数据类型的转换,如:

  1. Integer类:public static int parseInt(String s)
  2. Boolean类:public static boolean parseBoolean(String s)
public class AbstractDemo {
    public static void main(String[] args) {
        String s = new String("1");
        int num = Integer.parseInt(s);
        System.out.println(num*21);
    }
}
public class AbstractDemo {
    public static void main(String[] args) {
        boolean flagA = Boolean.parseBoolean(new String("true"));
        System.out.println(flagA);// 输出 true
        boolean flagB = Boolean.parseBoolean(new String("孙笑川"));
        System.out.println(flagB);// 字符不是true或false,都输出为false
    }
}

还可以将基本的数据类型转换为字符串类型,利用String类中的valueOf()方法

public class AbstractDemo {
    public static void main(String[] args) {
        int num = 10;
        String str = String.valueOf(num);
        System.out.println(str);
    }
}

三、接口

接口属于一种特殊的类,通过interface定义,在接口中可以定义全局常量、抽象方法(public方法)、default方法和static方法

  1. 接口需要被子类实现,子类利用implements关键字可以实现多个接口
  2. 子类如果不是抽象类,那么一定要覆写接口中的全部抽象方法
  3. 接口对象可以利用子类对象的向上转型进行实例化

关键字顺序 class 子类 [extends 父类] [implements 多个接口]

1. 接口的基本定义

使用接口

public class AbstractDemo {
    public static void main(String[] args) {
        IMessage msg = new Message();// 向上转型
        msg.printInfo();// 这个方法使用的是接口中的方法,但是方法体是子类中的方法体
    }
}
interface IMessage{
    public static final String INFO= "接口";
    public void printInfo();
}
class Message implements IMessage{
    @Override
    public void printInfo(){
        System.out.println("FUCK!");
    }
}

子类实现多个父接口

public class AbstractDemo {
    public static void main(String[] args) {
        IMessage msg = new Message();
        msg.printInfo();
    }
}

interface IMessage{
    public static final String INFO= "接口";
    public abstract void printInfo();
}
interface IChannel{
    public abstract boolean connect();
}

class Message implements IMessage, IChannel{
    @Override
    public void printInfo(){
        if (connect()){
            System.out.println("FUCK!");
        }
    }
    
    @Override
    public boolean connect(){
        return true;
    }
}
public class AbstractDemo {
    public static void main(String[] args) {
        IMessage msg = new Message();
        msg.printInfo();
        IChannel chl = (IChannel) msg;// 强制转换为IChannel接口实例
        System.out.println(chl.connect());// 才能调用该接口的connect方法
    }
}
interface IMessage{
    public static final String INFO= "接口";
    public void printInfo();
}
interface IChannel{
    public abstract boolean connect();
}
class Message implements IMessage, IChannel{
    @Override
    public void printInfo(){
        if (connect()){
            System.out.println("FUCK!");
        }
    }
    
    @Override
    public boolean connect(){
        return true;
    }
}

完整定义

interface IMessage{
    public static final String INFO = "孙笑川";
    public abstract String getInfo();
}

简化定义

interface IMessage{
    String INFO= "孙笑川";
    String getInfo();
}

子类继承抽象类同时实现接口

public class AbstractDemo {
    public static void main(String[] args) {
        IMessage msg = new Message();
        System.out.println(msg.getInfo());
    }
}
interface IMessage{
    String INFO= "接口";
    String getInfo();
}
interface IChannel{
    boolean connect();
}
abstract class DataBaseInfo{
    public abstract boolean databaseconnect();
}
class Message extends DataBaseInfo implements IMessage, IChannel{
    @Override
    public boolean connect(){
        return true;
    }

    @Override
    public boolean databaseconnect() {
        return true;
    }

    @Override
    public String getInfo() {
        if (connect()){
            if (databaseconnect()){
                return "连接成功!";
            } else {
                return "失败!";
            }
        } else{
            return "失败!";
        }
    }
}

定义抽象类的过程中所有的抽象方法必须有abstract关键字定义

使用extends继承多个父接口

public class AbstractDemo {
    public static void main(String[] args) {
        IMessage msg = new Message();
        System.out.println(msg.getInfo());
    }
}
interface IMessage{
    public static final String INFO= "接口";
    public abstract String getInfo();
}
interface IChannel{
    public abstract boolean connect();
}
interface IService extends IMessage,IChannel{// 使用extends实现接口继承接口
    public abstract boolean databaseconnect();
}
class Message implements IService{// 继承一个接口,实现所有的抽象方法
    @Override
    public boolean connect(){
        return true;
    }

    @Override
    public boolean databaseconnect() {
        return true;
    }

    @Override
    public String getInfo() {
        if (connect()){
            if (databaseconnect()){
                return "连接成功!";
            } else {
                return "失败!";
            }
        } else{
            return "失败!";
        }
    }
}

2. 接口定义加强

在接口中使用default定义普通方法

public class AbstractDemo {
    public static void main(String[] args) {
        IMessage msg = new Message();
        msg.printInfo();// 默认方法被继承,直接使用
        msg.printStaticInfo();// 静态方法直接调用
        System.out.println(msg.getInfo());
    }
}
interface IMessage{
    public static final String INFO= "接口";
    public abstract String getInfo();

    public default void printInfo(){// 定义了普通方法,可以直接被子类继承,但需要实例化接口才能使用
        System.out.println("默认方法");
    };
    public static default void printStaticInfo(){// 使用static定义,可以直接利用接口名称调用
        System.out.println("静态方法");
    }
}
interface IChannel{
    public abstract boolean connect();
}
interface IService extends IMessage,IChannel{
    public abstract boolean databaseconnect();
}
class Message implements IService{
    @Override
    public boolean connect(){
        return true;
    }

    @Override
    public boolean databaseconnect() {
        return true;
    }

    @Override
    public String getInfo() {
        if (connect()){
            if (databaseconnect()){
                return "连接成功!";
            } else {
                return "失败!";
            }
        } else{
            return "失败!";
        }
    }
}

使用过渡抽象类,继承多个接口,统一管理接口

public class AbstractDemo {
    public static void main(String[] args) {
        IMessage msg = new Message();
        msg.printInfo();
        System.out.println(msg.getInfo());
    }
}
interface IMessage{
    public static final String INFO= "接口";
    public abstract String getInfo();

    public default void printInfo(){
        System.out.println("默认方法");
    };
}
interface IChannel{
    public abstract boolean connect();
}
interface IService{
    public abstract boolean databaseconnect();
}
abstract class AbstractClass implements IMessage,IChannel,IService {
// 过渡抽象类统一管理多个接口
}
class Message extends AbstractClass{
    @Override
    public boolean connect(){
        return true;
    }

    @Override
    public boolean databaseconnect() {
        return true;
    }

    @Override
    public String getInfo() {
        if (connect()){
            if (databaseconnect()){
                return "连接成功!";
            } else {
                return "失败!";
            }
        } else{
            return "失败!";
        }
    }
}

3. 定义接口标准

public class AbstractDemo {
    public static void main(String[] args) {
        Computer labtap = new Computer();
        labtap.plugin(new Keyboard());
    }
}
class Computer{
    public void plugin(IUSB iusb){// 插入有USB接口的对象
        if (iusb.check()){
            iusb.work();
        }else{
            System.out.println("故障!");
        }
    }
}

interface IUSB{// 标准接口
    public abstract boolean check();
    public abstract void work();
}

class Keyboard implements IUSB{
    public boolean check(){
        return true;
    }
    public void work(){
        System.out.println("键盘连接成功");
    }
}

class Mouse implements IUSB{
    public boolean check(){
        return true;
    }
    public void work(){
        System.out.println("鼠标连接成功");
    }
}

4. 工厂设计模式

public class AbstractDemo {
    public static void main(String[] args) {
        IFood food = Factory.getInstance("bread");
        food.eat();
    }
}

interface IFood{
    public void eat();
}
class Bread implements IFood{
    public void eat(){
        System.out.println("吃面包");
    }
}
class Milk implements IFood{
    @Override
    public void eat(){
        System.out.println("喝牛奶");
    }
}
// 调用时不需要考虑具体的接口子类,只需要输入指定的数据标记,就可以获得对应的接口对象
class Factory{
    public static IFood getInstance(String className){
        if (className.equals("bread")){
            return new Bread();
        } else if (className.equals("milk")){
            return new Milk();
        } else {
            System.out.println("请输入正确的指标");
            return null;
        }
    }
}

5. 代理设计模式

public class AbstractDemo {
    public static void main(String[] args) {
        IEat eat = new EatProxy(new EatReal());
        eat.get();
    }
}

interface IEat{
    public void get();
}
class EatReal implements IEat{//设置代理类,客户端不必关心具体的实现
    public void get(){
        System.out.println("开始吃饭");
    }
}

class EatProxy implements IEat{
    private IEat eat;

    public EatProxy(IEat eat){
        this.eat = eat;
    }

    public void get(){
        this.prepare();
        this.make();
        this.eat.get();
        this.clear();
    }

    public void prepare(){
        System.out.println("准备素材");
    }
    public void make(){
        System.out.println("开始制作");
    }
    public void clear(){
        System.out.println("洗碗扫锅");
    }
}

6. 抽象类与接口的区别

No.区别抽象类接口
1关键字abstract classinterface
2组成常量、变量、抽象方法、普通方法、构造方法全局常量、抽象方法、普通方法、静态方法
3权限可以使用各种权限只能是public,普通方法使用default
4关系一个抽象类可以实现多个接口子类不能继承抽象类,却可以继承多接口
5使用使用extends继承抽象类子类使用implements实现接口
6设计模式模板设计模式代理设计模式,工厂设计模式
7局限一个子类只能继承一个抽象类一个子类可以实现多个接口

使用优先使用接口,避免使用抽象类

四、泛型

1. 泛型问题引出

public class AbstractDemo {
    public static void main(String[] args) {
        Point point = new Point();
        point.setX(10);
        point.setY(12);
        int x = (Integer)point.getX();
        int y = (Integer)point.getY();
        System.out.println("x = "+x+"、y = "+y);
    }
}
class Point{
    private Object x;
    private Object y;

    public void setX(Object x){// 使用Object类接受各种类型的对象
        this.x = x;
    }
    public void setY(Object y){
        this.y = y;
    }

    public Object getX(){
        return this.x;
    }
    public Object getY(){
        return this.y;
    }
}

2. 泛型基本定义

类中的属性或方法的参数与返回值的类型采用动态标记,在对象实例化的时候动态配置要使用的数据类型

public class AbstractDemo {
    public static void main(String[] args) {
        Point<Integer> point = new Point<>();// 使用各种引用数据代替泛型数据类型
        point.setX(10);
        point.setY(12);
        int x = point.getX();
        int y = point.getY();
        System.out.println("x = "+x+"、y = "+y);
    }
}
class Point<T>{// 泛型标记
    private T x;
    private T y;

    public void setX(T x){
        this.x = x;
    }
    public void setY(T y){
        this.y = y;
    }

    public T getX(){
        return this.x;
    }
    public T getY(){
        return this.y;
    }
}

3. 泛型通配符

为了可以适应所有本类的实例化对象,可以使用?作为泛型通配符使用,利用?表示的泛型类型只允许从对象中获取数据,不允许修改数据

public class AbstractDemo {
    public static void main(String[] args) {
        Message<String> msg = new Message<>();
        msg.setContent("孙笑川");
        fun(msg);
    }

    public static void fun(Message<?> temp){
        System.out.println(temp.getContent());
    }
}
class Message<T>{
    private T content;
    public void setContent(T content){
        this.content = content;
    }
    public T getContent(){
        return this.content;
    }
}

如果使用设置泛型,是否可以实现上述功能?

虽然可以接收各种不同的实例化对象,但是也可以随意修改数据,而?通配符只允许获取,不允许修改

形式1:public static void fun(Message<Object> temp){}
形式2:public static void fun(Message temp){}

虽然Object是String的父类,可以接收一切的数据类型,但是在泛型中Message<String>Message<Object>属于两个不同类型的对象

如果使用形式1的方式定义参数,则表示fun只能接收Message<Object>类型的引用

如果使用形式2的方式定义参数,可以解决不同泛型类型对象的传递问题,但也使得数据可以随意被修改

通配符“?”可以匹配任意类型的泛型类型外,也可以通过泛型上限和反省下限的配置实现更严格的类范围定义

【类和方法】可以使用(? extends 类)设置泛型上限:只能够使用类或当前类的子类设置泛型类型
?extends Number:可以设置Number或Number子类(例如,Integer类,Double类)

【方法】设置泛型下限(? super 类):只能够设置指定的类或指定类的父类
?super String:只能够设置String或者String的父类Object

1. 设置泛型上限
public class AbstractDemo {
    public static void main(String[] args) {
        Message<Integer> msg = new Message<>();
        msg.setContent(10);
        fun(msg);
    }
	// 设置了泛型的上限,实例化的对象Message只能使用Number和其子类作为泛型类型
    public static void fun(Message<? extends Number> temp){
        System.out.println(temp.getContent());
    }
}
class Message<T>{
    private T content;
    public void setContent(T content){
        this.content = content;
    }
    public T getContent(){
        return this.content;
    }
}
2. 设置泛型下限
public class AbstractDemo {
    public static void main(String[] args) {
        Message<String> msg = new Message<>();
        msg.setContent("孙笑川");
        fun(msg);
    }
    // 设置了泛型的下限,实例化的对象Message只能使用String和其父类Object作为泛型类型
    public static void fun(Message<? super String> temp){
        System.out.println(temp.getContent());
    }
}
class Message<T>{
    private T content;
    public void setContent(T content){
        this.content = content;
    }
    public T getContent(){
        return this.content;
    }
}

4. 泛型接口

定义泛型接口

interface IMessage<T> {
    public String echo(T msg);
}

定义泛型接口子类,在子类中继续声明泛型

public class AbstractDemo {
    public static void main(String[] args) {
        IMessage<String> msg = new IMessageImpl<>();
        msg.echo("孙笑川");
    }
}
interface IMessage<T>{
    public void echo(T msg);
}
class IMessageImpl<S> implements IMessage<S>{
    public void echo(S t){
        System.out.println("信息打印: "+ t);
    }
}

定义子类,在子类中为IMessage设置泛型类型

public class AbstractDemo {
    public static void main(String[] args) {
        IMessage<String> msg = new IMessageImpl();
        msg.echo("孙笑川");
    }
}
interface IMessage<T>{
    public void echo(T msg);
}
class IMessageImpl implements IMessage<String>{// 子类直接明确设置泛型类型
    public void echo(String t){
        System.out.println("信息打印: "+ t);
    }
}

5. 泛型方法

public class AbstractDemo {
    public static void main(String[] args) {
        Integer num[] = fun(1,2,3);
        for (int i : num){
            System.out.println(i + "、");
        }
    }
    public static <T> T[] fun(T... args){
        return args;
    }
}

此时是在一个没有泛型声明的类中定义了泛型方法,所以在fun()方法声明处就必须单独定义泛型标记,此时的泛型类型由传入的参数类型决定

总结

  1. java可以创建抽象类,专门当做父类。作用相当于模板,依据其格式来修改并创建新的类
  2. 抽象类包括普通方法和抽象方法,抽象方法没有方法体,要交给继承的子类进行强制性覆写
  3. 抽象类不能用new实例化对象,必须通过对象的多态性利用子类对象的向上转型进行实例化操作
  4. 接口是方法和全局常量的集合,接口必须被子类实现,子类单继承,接口多继承,接口通过多个extends继承多个接口
  5. 接口中允许default定义普通方法以及static定义的静态方法
  6. 接口也可以派生接口,或者称为子接口,不但保留父接口成员方法,还能添加自己的接口方法
  7. 使用泛型可以避免使用Object接受参数所带来的ClassCastException问题
  8. 泛型对象可以进行引用类型时一定要使用通配符?(或相关上限,下限设置)来描述泛型参数

习题

// 工厂代理模式,实现圆形正方形的抽象类设计
public class AbstractDemo {
    public static void main(String[] args) {
        Shape circle = Factory.getInstance("circle",2.4);
        System.out.println(circle.area());
        System.out.println(circle.perimeter());
        Shape perimeter = Factory.getInstance("正方形", 2.4,24.3);
        System.out.println(perimeter.area());
        System.out.println(perimeter.perimeter());
    }
}
abstract class Shape{
    public abstract double area();
    public abstract double perimeter();
}
class Circle extends Shape{
    private double r;
    public Circle(double r){
        this.r = r;
    }
    @Override
    public double area() {
        return 3.14*Math.pow(this.r, this.r);
    }

    @Override
    public double perimeter() {
        return 2*3.14*this.r;
    }
}
class Rectangle extends Shape{
    private double x;
    private double y;
    public Rectangle(double x, double y){
        this.x = x;
        this.y = y;
    }

    public double area(){
        return this.x*this.y;
    }

    public double perimeter(){
        return 2*(this.x+this.y);
    }
}
class Factory{
    public static Shape getInstance(String className, double... args){
        if (className.equalsIgnoreCase("circle")){
            return new Circle(args[0]);
        } else if(className.equalsIgnoreCase("正方形")){
            return new Rectangle(args[0],args[1]);
        }
        else {
            return null;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值