面向对象:封装、继承、多态、接口

封装

在实际开发中对于某些java类中包含一些敏感的信息,这些信息希望外界无法随机访问,此时就需要使用一种机制来实现信息(数据)的隐藏;通常情况下需要隐藏对象的信息,可以使用private修饰符来进行隐藏,将属性设置成私有化属性

例如:

public class People {
    //姓名
    private String name;
    private int age;
    private char sex;
}

通过对以上的信息进行隐藏之后,虽然信息是隐藏了,但是外界再也无法访问,无法为属性赋值或者是拿到属性值这种情况在实际开发种显然不合理,针对这种问题的解决思路是:提供公开的方法去进行访问,单独去为每个属性设置值(setter方法)或者是获取(getter方法)值

具体写法如下:

public class People {
    //姓名
    private String name;
    private int age;
    private char sex;
    //是否婚否
    private boolean marry;

    public People() {
    }

    public People(String name, int age, char sex, boolean marry) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.marry = marry;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public boolean isMarry() {
        return marry;
    }

    public void setMarry(boolean marry) {
        this.marry = marry;
    }
}

1、static关键字

static修饰的元素跟对象无关,与类直接无关,即需要使用这些元素,只需要

通过类名来访问即可(无需创建对象)。对于这些被static修饰的元素也有一些特定的名词:

  • 类变量

所谓的类变量就是静态变量,使用static修饰的成员变量就叫做类变量,类变量与对象就没有任何关系,类变量的值直接由类来控制,是一个所有对象都可以共享的变量,只要由一个对象将其修改了,所有对象看到的都是修改后相同的值,类变量的初始时间是在类加载的时候初始化,而不是在对象创建时

类变量,成员变量,局部变量生命周期?

  • 当对象中的成员方法执行完毕之后,方法内部的局部变量就会被回收;

  • 当对象使用结束之后,GC回收会清理对象,同时将对象中成员变量申请的内存空间清理;

  • 当JVM结束的时候,才会清理static变量;

  • 类方法

所谓的类方法就是静态方法,使用static修饰成员方法,被修饰的方法与对象无关,在访问类方法时,直接使用类名.方法,无需创建对象调用

调用类方法时分为两种情况:

  1. 在同一个类中调用,直接使用方法名()调用

  2. 在不同类中调用,使用类名.方法名()

如下:

Math.random();

Arrays.sort();

2、ArrayList使用

常用的方法:

  • add(E e):添加一个元素到集合中

  • get(int index):获取指定位置的元素

  • remove(int index):删除指定位置的元素

  • size():获取集合中实际元素的个数

  • clear():清空集合中的所有元素

一般语法:

 ArrayList list = new ArrayList();

3、方法重载

重载(Overload)是java中多态性的实现策略,一个方法多种表现形式;

重载即一个类或者接口中存在多个同名的方法,但是这些方法的参数必须不同(个数/类型/顺序 任意一项必须不同)

如下:

 //计算面积
    public void area() {
        
    }
    
    //计算正方形的面积
    public void area(int width,int height){
        
    }
    
    //计算圆的面积
    public void area(double banjing){
        
    }
    
    
    //计算三角形的面积
    public void area(int di,double height){
        
    }

继承

1、类与类之间的关系

根据类之间的关系划分,主要分为两大类别:

·横向关系:平级关系

·纵向关系:上下级关系

横线关系:

  • 依赖关系

所谓的依赖关系,指的就是一个对象在完成某个特定功能的时候,依赖于另一个对象作为支持,

例如:猫抓老鼠 游戏中,猫类的捕获(catchMouse)方法的实现需要老鼠(Mouse)对象来完成

public class Cat{
    public boolean catchMouse(Mouse m){
        
    }
}
  • 关联关系

    • 聚合关系

    • 组合关系

关联关系是一种较弱的类之间的练习,通常指的是类之间的一种简单关联,例如:一对一,一对多,多对多,在代码的层面上表示:在一个类中,将另一个类的对象作为属性定义在当前类中:

部门类:

/**
 * 部门类      1
 */
public class Dept {
    private int dno;
    private String dname;
    private String tel;
    //当前部门下的员工集合
    //private ArrayList<Emp> emps = new ArrayList<>();

员工类:

/**
 * 员工类      N
 */
public class Emp {

    private int eno;
    private String ename;
    private String job;
    private double sal;
    //将部门对象作为员工的属性定义出来,这样依赖,一旦获取到员工对象,就可以将员工所属的部门信息全部获取
    private Dept dept;

纵向关系

java中除了横向关系之外,另外还包括一种纵向关系,这种关系更多是体现在上下级的关系:

  • 继承关系(extends)

  • 实现关系(implements)

2、继承关系中构造器的执行顺序问题

根据程序执行结果:在继承关系中构造器的执行顺序按照继承的层次结构,从顶层父类开始依次向下执行(即:先执行父类构造器,再执行子类构造),由于所有的构造中的this最终的输出都是同一个对象地址,因此整个过程只创建了一个对象,创建了一个子类对象

public class GrandFather {
    public GrandFather() {
        System.out.println("GrandFather构造器执行"+this);
    }
}

class Father extends GrandFather {

    public Father() {
        System.out.println("Father构造器执行"+this);
    }
    
}

class Son extends Father {
    public Son() {
        System.out.println("Son构造器执行"+this);
    }

    public static void main(String[] args) {
        //创建Son对象
        new Son();
    }
}

上述代码的执行结果:

GrandFather构造器执行com.softeem.Son@1b6d3586
Father构造器执行com.softeem.Son@1b6d3586
Son构造器执行com.softeem.Son@1b6d3586

如果创建对象的时候给到参数,则会执行有参构造器,如果有参构造器调用父类构造器则也会执行的是父类的构造器。

如下:

public class GrandFather {
    private int a;
    public GrandFather() {
        System.out.println("GrandFather构造器执行"+this);
    }

    public GrandFather(int a) {
        this.a = a;
        System.out.println("GrandFather有参构造器");
    }
}

class Father extends GrandFather {
    private int b;
    public Father() {
        System.out.println("Father构造器执行"+this);
    }

    public Father(int a, int b) {
        super(a);
        this.b = b;
        System.out.println("Father有参构造器");
    }
}

class Son extends Father {
    private int c;
    public Son() {
        System.out.println("Son构造器执行"+this);
    }

    public Son(int a, int b, int c) {
        super(a, b);
        this.c = c;
        System.out.println("Son有参构造器执行");
    }

    public static void main(String[] args) {
        //创建Son对象
        Son s= new Son(1,2,3);
    }
}

运行结果如下;

GrandFather有参构造器
Father有参构造器
Son有参构造器执行

3、方法重写

方法重载(Overload):方法名相同,参数类型不同(顺序/数量/类型 满足其中一种就行)

方法重写(Override):就是子类在调用父类的方法时,对父类的方法进行修改(重新定制) 。

重写注意事项:

构成方法重写,以及重写过程中需要注意一些问题:

  1. 方法的重写必须发生在存在继承关系(实现关系)的子类中(子类重写父类方法)

  2. 被重写的方法的方法名必须与父类中的方法名保持一致,参数列表返回值类型也得保持一致遵循三同一不严格:方法名相同,参数列表相同,返回值相同,子类重写的方法的访问修饰符的范围要大于等于父类中方法的修饰符范围。修饰符范围:public > protected > default > private

  3. 尽量在被重写的方法上方添加上@override注解,用来检查该方法是否属于重写

  4. 当父类中的方法不满足子类需求的时候,子类可以对父类中的方法进行重写

  5. 构造器不能够被重写

重写(override)和重载(overload)的区别:

  • 重写和重载都属于多态性的体现(同一个名称的方法,不同的实现流程:同名方法的不同形态)

  • 重写必然需要在存在继承关系的子类中,重载可以发生在同一个类中,也可以发生在存在继承关系的父子类中

  • 重写遵循三同一不严格原则,重载只要求方法名相同,参数列表不同

  • 构造器可以被重载,但是不能被重写

4、总结

当一个类去继承另外一个类之后:

  • 被继承的类称之为父类(超类/基类:super class),而继承的类称之为子类(subclass)

  • 子类继承父类后,父类中的所有非私有化元素(属性,方法)都可以被子类使用

  • java中不存在跟c++的多继承,(一个子类多个父类),但是可以支持多重继承(C继承B,B继承A)

  • 父类中被protected修饰的元素,即便是跨包也能够被子类访问到

  • 在创建子类对象时,首先调用的是父类的构造器(不是创建对象)

  • 如果父类中不存在无参构造器,则在调用子类构造器时需要使用super手动调用父类构造器

  • 构造器不能够被继承,只能被调用

多态

java的引用数据类型,存在两种不同的表现形式:第一种:编译时类型,第二种:执行时类型,当一个应用数据类型它的编译时类型和执行时类型不一致时,此时我们就认为这个引用类型为多态,符合java的有关多态性的定义。

案例如下:

People:

public class People {
    private String name;
    private int age;
    //构造器
    //getter/setter
    //equals/hashCode
    //toString
}

Student

public class Student extends People{
    private String username;
    private String pwd;
     //构造器
    //getter/setter
    //equals/hashCode
    //toString
}
public class TestPeople {
    public static void main(String[] args) {
        //正常的创建对象
        Student s = new Student();

        //还可以采用如下方式来进行对象的创建
        //父类对象引用指向子类对象
        People p = new Student();

    }
}

以上People p = new Student();在编译期间类型表示为People,但是在实际运行的时候,对象p会被作为Student类型进行处理,这种处理方式称之为动态绑定,这种声明方式,我们称之为:父类对象引用指向子类对象

(向上转型)。

1、equals

在java一般进行比较运算的时候通常使用==,但是==在对于基本数据类型的时候,比较的时两个值是否相等,但是在进行引用数据类型数据进行比较时,比较的是两个引用数据类型的内存地址:

所以如果想要比较引用数据类型,就需要用到equals

如下:

System.out.println(u1.equals(u2))

语句的是意思就是比较u1和u2是否相同

2、instanceof

instanceof运算符是一个java中的关键字,作用是用于判断指定的变量/对象是否是目标类型或者是

目标类型的子类类型,例如:

if (anObject instanceof String) {
     
   }

以上代码的意思是:判断anObject变量表示的类型是否是String类型

3、下转型

多态除了支持父类引用指向子类对象的同时,也支持使用子类引用指向父类对象。(实际的指向还是子类对象)

  public static void main(String[] args) {
        Object o = new Object();

        //将父类对象使用子类引用表示(下转型,前提是父类对象运行时的类型为子类类型)
        //java.lang.ClassCastException
        //Dog d = (Dog) o;
        //System.out.println(d);
        //向上转型
        Object o2 = new Dog("来福", 1);
        //向下转型
        Dog d2 = (Dog) o2;
        System.out.println(d2);
   }

4、多态的好处

  1. 提高程序的扩展性

  2. 解除类与类之间的耦合度

抽象和接口

1、关于抽象类

·抽象类不能够被实例化(不能通过构造来创建对象,可以通过匿名内部类对抽象方法进行实现之后创建对象)

public static void main(String[] args) {
        //调用不到构造器
        //People p = new People();

        //通过匿名内部类对抽象方法实现后创建对象
        People p = new People() {
            @Override
            public void working() {

            }
        };
    }

·抽象类可以拥有构造器(普通类中能定义的,抽象类中都能定义)

·抽象类中可以包含普通方法和抽象方法 

public abstract class People {
    private String name;
    private int age;

    public People() {
    }

    //普通方法
    public void eat() {

    }

    //上班/上学     抽象方法
    public abstract void working();
}

·一个类如果拥有抽象方法,那么这个类一定是抽象类

·抽象方法不能存在方法体,只是一种方法的声明

·抽象类可以继承抽象类(存在多个抽象类继承,那么子类一旦实现,就需要将所有的抽象方法全部实现)

·抽象类可以有多个多个子类

·非抽象类如果继承抽象类,那么就必须将抽象类中所有的抽象方法全部重写(实现)

·一个类如果是一个抽象类,那么大概率情况下存在抽象方法。

2、接口概述

如果说java中抽象类还不够抽象,不够纯粹,接口则是一个更为抽象的,更纯粹的抽象类,接口是一种特殊的抽象类接口更多时候是一种标注的形式出现,是一个象征,接口不是一个类,是一个方法的集合

接口的声明语法:

[访问修饰符] interface 接口名称{
    //常量
    //抽象方法
    //1.8新增了静态方法,默认方法
}

接口特点

接口就是一种更纯粹的抽象类,是一种标准定义,本身不具备任何实现,存在以下特点:

  1. 接口不是一个类

  2. 接口中只能包含:常量,抽象方法(JDK8之前)

  3. 接口不存在任何的构造器,因此无法被实例化。

  4. 接口可以被子类实现,并且一个类可以实现多个接口(解决了类单继承的局限性),必须实现所有接口中的抽象方法;

  5. 抽象类可以实现接口,甚至不用实现接口的方法

  6. 接口不能实现接口,接口可以继承接口,甚至支持多继承

接口是行为的抽象

抽象类是对类型的一种抽象

抽象类和接口使用哪一个:

优先选择接口,尽量少用抽象类,所有方法的定义方法的实现彻底分离

接口和抽象类的区别:

相同点:
    都是位于继承的顶端,用于被其他类继承或者实现
    都可以定义抽象方法,由子类/实现类来实现方法
    都不能创建对象
    
不同点:                抽象类                                          接口
关键字                    abstract                                  interface
内部成员:        类能定义的抽象类都能定义       静态常量,default方法,抽象方法,静态方法
抽象方法            必须声明abstract                         可以省略public abstract
构造器                    可以定义构造器                        没有构造器
和类的关系                继承关系,单继承                实现关系,多实现

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值