Java之面向对象三大特性简介

前言

面向对象三大特性简介,继承、封装、多态。

一、继承

1、继承的主要作用

1)代码复用,更加容易实现类的扩展,类之间又有很多共性,避免写更多冗余的代码。
2)方便对现实世界建模,因为现实世界大多数都是继承关系。
在这里插入图片描述

2、继承的实现

用extends来实现,class A extends B,A 扩展了 B。

public class Person {
    String name;
    Person friend;

    public static void main(String[] args) {
        Person p1 = new Person();
        Person p2 = new Person();
        p1.friend = p2;
        p2.friend = p1;
        p1 = p2 = null;
    }
}
class Teacher extends Person{
    //Teacher除了有name和朋友,还有所属学校
    //String name;
    //Person friend;
    String universityName;
}

3、继承使用要点

1)为了避免多继承造成复制的继承链,系统难于维护,Java中只能单继承。
2)Java类中没有多继承,但接口有多继承。
3)子类继承父类,能得到父类除构造器的成员变量和成员方法,但不见得可以直接访问(比如父类的私有属性和方法)
4)如果一个Java类没有显示继承,则会隐式继承java.lang.Object类。
5)可通过instanceof来判断类的类型。
p1 instanceof Person,结果为Boolean变量

4、方法的重写Override

子类重写父类的方法,可以通过自身的行为替代父类的行为。方法的重写是实现多态的必要条件。
三特点
1)“==”,方法名、形参列表相同。
2)“<=”,子类异常要是父类异常的子类或者本异常。这跟动态绑定有关。
3)">=",访问权限,子类大于父类。
之类重写的方法前面给的修饰权限要大于等于父类。public > protected>default>private.
注:属性没有这一说法,子类写了一个同名属性,没有这种权限关系,调属性时,先调子类属性,没有再根据权限来调父类属性。如果是父类对象调同名属性,那只能调父类的属性。没有所谓的属性运行时多态。

在这里插入图片描述

public class Person {
    String name;
    Person friend;

    public void sleep(){
        System.out.println("睡觉");
    }
    public static void main(String[] args) {
        Person p1 = new Person();
        Person p2 = new Person();
        p1.friend = p2;
        p2.friend = p1;
        p1 = p2 = null;
    }
}
class Teacher extends Person{
    //Teacher除了有name和朋友,还有所属学校
    String universityName;

    //不一样的睡觉
    @Override
    public void sleep(){
        System.out.println("去办公室");
        super.sleep();
    }
}

5、Final关键字

1)FInal修饰变量,该变量变为常量,一经复制,就不能再修改。
2)Final修饰方法,该方法不能被重写,但是可以重载。
3)Final修饰类,该类不能被扩展,即继承,如String、Math类。

final class Teacher extends Person{
    //Teacher除了有name和朋友,还有所属学校
    String universityName;

    //不一样的睡觉
    @Override
    public void sleep(){
        System.out.println("去办公室");
        super.sleep();
    }
    final int MOD = 4;
    public final int mod(int n){
        return n % MOD;
    }
}

6、继承和组合

组合)将父类对象作为子类的属性,通过这个父类属性来调用父类的属性和方法,更加灵活。

class Teacher {
    
    String universityName;
    Person p;
    //不一样的睡觉
    
    final int MOD = 4;
    public final int mod(int n){
        return n % MOD;
    }

    public static void main(String[] args) {
        Teacher t = new Teacher();
        t.p = new Person();
        t.p.sleep();
    }
}

总结)组合虽然灵活,但也要分情况,为了更好的建模,当属于is-a的时候,就使用继承;当属于has a 的时候,就使用组合。
如Teacher is a Person更加恰当,所以用继承,能更好的建模。
如Computer has a Chip,此时使用组合更恰当。因为电脑虽然要用芯片里的方法,但是继承它不太合理,逻辑混乱。

二、Object类

1、Object类基本特性

Object类是所有类的根基类,所有Java类的根基类都是Object类,继承了Object类的属性和方法,但因权限问题,不一定能全部访问。

2、toString方法

JDK Object类的源码及注释,大概意思就是返回类名+@+对象地址

    /**
     * Returns a string representation of the object. In general, the
     * {@code toString} method returns a string that
     * "textually represents" this object. The result should
     * be a concise but informative representation that is easy for a
     * person to read.
     * It is recommended that all subclasses override this method.
     * <p>
     * The {@code toString} method for class {@code Object}
     * returns a string consisting of the name of the class of which the
     * object is an instance, the at-sign character `{@code @}', and
     * the unsigned hexadecimal representation of the hash code of the
     * object. In other words, this method returns a string equal to the
     * value of:
     * <blockquote>
     * <pre>
     * getClass().getName() + '@' + Integer.toHexString(hashCode())
     * </pre></blockquote>
     *
     * @return  a string representation of the object.
     */
    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

可在类中重写toString方法,具有自己的独特性,而不是只有地址。

public class Person {
    String name;
    Person friend;

    public void sleep(){
        System.out.println("睡觉");
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", friend=" + friend +
                '}';
    }
    public static void main(String[] args) {
        Person p1 = new Person();
        //输出p1,会自动调p1.toString()
        System.out.println(p1);
    }
}

3、== 和equals方法

    public boolean equals(Object obj) {
        return (this == obj);
    }

在Object中,equals的原理就是==,它比较的是两个对象的地址,而如果两个对象的属性相等时,我们认为它俩相等,此时需重写equals方法。

@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return name.equals(person.name) &&
                friend.equals(person.friend);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, friend);
    }

name去比较的时候也用了equals,String的equals也是重写了的,注释及源码如下。

/**
     * Compares this string to the specified object.  The result is {@code
     * true} if and only if the argument is not {@code null} and is a {@code
     * String} object that represents the same sequence of characters as this
     * object.
     *
     * <p>For finer-grained String comparison, refer to
     * {@link java.text.Collator}.
     *
     * @param  anObject
     *         The object to compare this {@code String} against
     *
     * @return  {@code true} if the given object represents a {@code String}
     *          equivalent to this string, {@code false} otherwise
     *
     * @see  #compareTo(String)
     * @see  #equalsIgnoreCase(String)
     */
    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String aString = (String)anObject;
            if (coder() == aString.coder()) {
                return isLatin1() ? StringLatin1.equals(value, aString.value)
                                  : StringUTF16.equals(value, aString.value);
            }
        }
        return false;
    }

4、 super关键字

可以看做直接父类的引用。
构造函数)在子类的构造函数中,如果没有显示的调用super(…),会隐式调用super()

public Person(){
        System.out.println("调用Person的构造器");
    }
package com.xhu.java;

public class Teacher extends Person {

    String universityName;
    Person p;
    //不一样的睡觉
    public Teacher(){
        System.out.println("调用Teacher构造器");
    }
    final int MOD = 4;
    public final int mod(int n){
        return n % MOD;
    }

    public static void main(String[] args) {
        System.out.println("准备new一个对象");
        Teacher t = new Teacher();
    }

}

在这里插入图片描述

5、继承树的追溯

在这里插入图片描述
这是继承树的追溯过程。
先构建父类,然后父类执行构造函数,赋值操作,再构建子类对象,然后赋值操。

三、封装

合理的封装让外部调用方便,也便于自己修改代码。

1、封装的作用

“高内聚、低耦合”,高内聚:内部数据操作细节完成,不允许外部干涉;低耦合:只暴露少量方法给外部使用,方便外部调用。
封装的优点:
1)代码的安全性
2)代码的复用性
3)高内聚:封装细节,便于修改内部代码,从而提高可维护性。
4)低耦合:简化外部调用,便于调用者使用,从而便于协作。

2、封装的实现-使用访问控制符

在这里插入图片描述
对于protected,若子类和父类在同一包中,子类可以访问父类的protected成员,也可以访问父类任意对象的protected成员;若子类和父类不在同一包中,子类只可以访问父类的protected成员,不能访问任意父类对象的protected成员。

class Person {
    protected String name;
}

下面的访问属于访问父类的projected的成员:

public class Teacher extends Person {

    String universityName;
   
    public void testProtected(){
        System.out.println(super.name);
    }
  

}

下面的访问属于访问父类任意对象的projected的成员:

public class Teacher extends Person {

    String universityName;
  
    public static void main(String[] args) {
        Teacher t = new Teacher();
        System.out.println(t.name);
    }

}

3、封装使用的细节

1)对于成员变量,一般是private修饰,然后提供get、set方法来访问。
2)本类提供给它类调用的方法设为public,本类中的辅助方法,用private修饰。
JavaBean的封装演示:

package com.xhu.java;

public class Teacher extends Person {

    private String universityName;
    private boolean flag;

    public String getUniversityName() {
        return universityName;
    }

    public void setUniversityName(String universityName) {
        this.universityName = universityName;
    }

    public boolean isFlag() {
        return flag;
    }
 	public Teacher(){
        System.out.println("调用Teacher构造器");
    }
    public Teacher(String universityName) {
        this.universityName = universityName;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "universityName='" + universityName + '\'' +
                ", name='" + name + '\'' +
                ", friend=" + friend +
                '}';
    }
}

四、多态

1、多态概念和实现

由于继承与方法重写的原因,多态是指调用同名重载方法,对象不同可能会有不同的行为。
比如Person类的睡觉就是简单的睡觉,而继承它的Teacher类和Student类的sleep()方法不同。

Person p1 = new Teacher();
Person p2 = new Student();
p1.sleep();
p2.sleep();
//out
//老师的休息
//学生的休息

多态)多态是方法的多态,不是属性的多态。
多态存在的三个条件)继承、方法重写、父类引用指向之类对象。
多态出现)父类引用指向子类对象后,父类引用调用子类重写的方法,多态出现。
为什么要用父类引用指向子类对象?当一个类被很多类继承时,传入一个子类对象,然后调一个同名函数,此时就要判断这个对象到底是那个子类对象,而此时可以用父类接收对象,通过运行时的多态来决定具体调那个子类的重写函数(通过instanceof来判断的)。此时代码就简介了很多。
需要重载多个函数。

public void test(Teacher t){
        t.sleep();
    }
    public void test(Student s){
        s.sleep();
    }
    public void test(Postgraduate po){
        po.sleep();
    }

通过多态,简化代码

public void test(Person p){
        p.sleep();
    }

2、对象的转型

public static void main(String[] args) {
		//编译时,只认p为Person对象。
        Person p = new Teacher();//向上类型转化,自动完成。
        Teacher t = (Teacher) p;//向下类型转化,强制完成。
    }

但是为了防止异常,我们需要手动处理一下:

public static void main(String[] args) {
        Person p = new Teacher();//向上类型转化,自动完成。
        Teacher t = null;
        if(p instanceof Teacher)
            t = (Teacher) p;//向下类型转化,强制完成。
    }

总结

1)封装
2)继承
3)多态

参考文献

[1] Java SE 高淇

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值