Java学习笔记-面向对象

245 阅读8分钟

面向对象的三种主要特性:封装、继承、多态。

1.类与对象

1.1 类与对象的基本概念:

  • 类是一个基本模板,代表着一个共性的特征集合。比如男人和女人都是人。
  • 对象是具体的每个人,是类的实例,比如每个人都有不同的属性、技能。

1.2 类与对象的基本定义:

类的定义:

// 定义一个人的类
class Person {
    String name;
    int age;
    String sex;
    public void getInfo() {
        System.out.println("姓名:" + name + ",年龄:" + age + ",性别:" + sex);
    }
}

对象的定义:

Person xiaohong = new Person();
// 类名称 对象名称 = new 类名称();

xiaohong.name = "小红";
xiaohong.age = 18;
xiaohong.sex = "girl";
xiaohong.getInfo();
// 姓名:小红,年龄:18,性别:girl

2.封装性

上文1.2定义的类的属性,外部可直接修改,这是不符合实际业务开发逻辑的。因此,我们使用private关键字进行封装,将类的属性私有化,并定义相应的gettersetter方法,区分别获取属性、修改属性。

修改后的类和对象:

class Person {
    private String name;
    private int age;
    private String sex;
    public void setName(String newName){
        name = newName;
    }
    public void setAge(int newAge){
        age = newAge;
    }
    public void setSex(String newSex){
        sex = newSex;
    }
    public void getInfo() {
        System.out.println("姓名:" + name + ",年龄:" + age + ",性别:" + sex);
    }
}


public class Test {
    public static void main(String[] args){
        Person xiaohong = new Person();
        xiaohong.setName("xiaowang");
        xiaohong.setAge(22);
        xiaohong.getInfo();
    }
}
// >> 姓名:xiaowang,年龄:22,性别:null

3.构造方法

构造方法是一种特殊的方法,它只在新对象实例化的时候调用。

定义原则:

  • 方法名称与类的名称相同
  • 没有返回值类型声明
  • 构造方法可以重载

定义构造方法:

class Person{
    public Person(){                // 构造方法,不必声明返回值类型
        System.out.println("Hello");
    }
}

构造方法核心作用:

将类对象实例化时设置属性的初始化内容。

class Person {
    private String name;
    private int age;
    private String sex;

    public Person(String n, int a, String s) {
        setName(n);
        setAge(a);
        setSex(s);
        System.out.println("姓名:" + name + ",年龄:" + age + ",性别:" + sex);
    }
    public void setName(String newName){
        name = newName;
    }
    public void setAge(int newAge){
        age = newAge;
    }
    public void setSex(String newSex){
        sex = newSex;
    }
    public void getInfo() {
        System.out.println("姓名:" + name + ",年龄:" + age + ",性别:" + sex);
    }
}


public class Hello {
    public static void main(String[] args){
        Person xiaohong = new Person("xiaowang",22,"boy");
    }
}
// >> 姓名:xiaowang,年龄:22,性别:boy

4. this关键字

4.1 访问类属性都要加上this

class Person {
    private String name;
    private int age;
    private String sex;

    public Person(String name, int age, String sex) {
        setName(name);
        setAge(age);
        setSex(sex);
        System.out.println("姓名:" + this.name + ",年龄:" + this.age + ",性别:" + this.sex);
    }
    public void setName(String newName){
        this.name = newName;
    }
    public void setAge(int newAge){
        this.age = newAge;
    }
    public void setSex(String newSex){
        this.sex = newSex;
    }
    public void getInfo() {
        System.out.println("姓名:" + this.name + ",年龄:" + this.age + ",性别:" + this.sex);
    }
}


public class Hello {
    public static void main(String[] args){
        Person xiaohong = new Person("xiaowang",22,"boy");
    }
}
// >> 姓名:xiaowang,年龄:22,性别:boy

4.2 调用本类方法

  • 调用本类普通方法:this.getInfo()
  • 调用奔类构造方法:this()this(a,b)

4.3 表示当前对象

this 指向当前对象

5. 继承性

5.1 继承的实现

class 子类 extends 父类 {}

  • 子类又称派生类
  • 父类又称超类(Super Class)
  • 子类的构造方法中,可以通过super访问父类的构造方法和普通方法
  • 子类的普通方法中,只能通过super访问父类的普通方法

5.2 继承的限制

限制1:Java不允许多重继承,只允许多层继承。

但是可以使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口

public interface A { 
    public void eat(); 
    public void sleep(); 
} 
public interface B { 
    public void show(); 
} 
public class C implements A,B { }

限制2:子类继承父类时,对于所有的私有操作属于隐式继承,而所有的非私有操作属于显示继承

也就是说,子类要想访问父类的私有属性,必须通过getter和setter

限制3:在子类对象构造前一定会默认调用父类的构造(默认使用无参构造),以保证父类的对象先实例化,子类对象的后实例化

class Parent {
    public Parent(){
        System.out.println("父亲");
    }
}

class Son extends Parent {
    public Son(){
        System.out.println("儿子");
    }
}

public class Hello{
    public static void main(String args[]){
        new Son();
    }
}

// >> 父亲
// >> 儿子

6. 覆写(Override)

class Parent {
    public void fun(){
        System.out.println("父亲");
    }
}

class Son extends Parent {
    public void fun(){
        System.out.println("儿子");
    }
}

public class Hello{
    public static void main(String args[]){
        Son son = new Son();
        son.fun();
    }
}

// >> 儿子

7. 多态性

多态性主要体现在:

方法的多态性:

  • 重载:同一个方法名称,根据不同的参数类型及个数可以完成不同的功能
  • 覆写:同一个方法,根据实例化的子类对象不同,所完成的功能也不同

对象的多态性:

  • 向上转型:子类对象变成父类对象,格式:父类 父类对象 = new 子类(); 自动转换
  • 向下转型:父类对象变为子类对象,格式:子类 子类对象 = (子类)父类实例; 强制转换

对象多态性的作用:

在实际的开发中,对象向上转型的主要意义在于参数的统一,也是最为主要的用法,而对象向下转型指的是调用子类的个性化操作方法。

8. 抽象类

8.1 抽象类的定义

抽象方法是指没有方法体的方法,也就是声明方法时不加{},加上abstract声明。

拥有抽象方法的类属于抽象类。

抽象类只比普通的类多了抽象方法的定义,其他结构与普通类完全一样。

abstract class A {
    public void fun() {
        System.out.println("存在有方法体的方法!");
    }
    public abstract void print();
}

8.2 抽象类的使用原则

  1. 抽象类必须有子类,即每一个抽象类一定要被子类所继承。

  2. 抽象类的子类必须覆写抽象类中的全部抽象方法(强制子类覆写)。

  3. 依靠对象的向上转型概念,可以通过抽象类的子类完成抽象类的实例化对象操作。

abstract class A {
    public void fun() {
        System.out.println("存在有方法体的方法!");
    }
    public abstract void print();
}

class B extends A {
    public void print(){
        System.out.println("抽象类的子类");
    }
}

public class Hello{
    public static void main(String args[]){
        A a = new B(); // 向上转型
        a.print(); // 调用子类覆写过的方法
    }
}

8.3 抽象类应用——模板设计模式

暂时接触不到,后期再来补充

9. 接口(暂不考虑JDK1.8对接口的影响)

接口是一个特殊的类,这个类里面只有抽象方法与全局变量。

interface A {                                 // 定义接口
    public static final String MSG = "YOOTK"; // 全局变量
    public abstract void print();             // 抽象方法
}

9.1 接口的使用原则

  • 接口必须有子类,此时子类可通过implements关键字实现多个接口
  • 接口的子类(如果不是抽象类),必须要覆写接口中的全部抽象方法
  • 接口的对象可以利用子类对象的向上转型进行实例化操作
interface A {
    String MSG = "Hello";
    public void print();
}

interface B {
    public void get();
}

class X implements A,B {
    public void print() {
        System.out.println("A接口的抽象方法");
    }
    public void get() {
        System.out.println("B接口的抽象方法");
    }
}

public class Hello{
    public static void main(String args[]){
        X x = new X();              // 实例化子对象 
        A a = x;                    // 向上转型
        B b = x;                    // 向上转型
        a.print();
        b.get();
        System.out.println(A.MSG);
    }
}

9.2 接口的应用-标准

9.3 接口的应用-工厂设计模式

工厂设计模式:客户端无需关注具体的子类,只需要关注如何取得接口对象并且操作。

如下面的Friut接口,定义了两个子类Apple和Orange覆写eat的方法,同时定义了一个Factory类,对外提供获取两个子类实例的接口,在main函数直接调用Factory.getInstance("apple")方法获取Apple的实例。

interface Fruit {
    public void eat();
}

class Apple implements Fruit {
    public void eat() {
        System.out.println("吃苹果");
    }
}

class Orange implements Fruit {
    public void eat() {
        System.out.println("吃橘子");
    }
}

// 定义工厂类,提供获取两个子类实例的方法 getInstance()
class Factory {
    public static Fruit getInstance(String className) {
        if("apple".equals(className)){
            return new Apple();
        }else if("orange".equals(className)){
            return new Orange();
        }else{
            return null;
        }
    }
}

public class Hello{
    public static void main(String args[]){
        Fruit f = Factory.getInstance("apple");
        f.eat();
    }
}

9.4 接口的应用-代理设计模式(Proxy)

代理设计就是指一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其他相关业务的处理

IMG_20210910_195329.jpg


interface NetWork {
    public void browse();
}

// 真实的上网操作
class Real implements NetWork {
    public void browse(){
        System.out.println("上网浏览信息");
    }
}

// 代理上网
class Proxy implements NetWork {
    private NetWork netWork;
    public Proxy(NetWork netWork){
        this.netWork=netWork;
    }
    public void check() {
        System.out.println("检查合法性");
    }

    @Override
    public void browse() {
        this.check();
        this.netWork.browse();
    }
}

public class Hello{
    public static void main(String args[]){
        NetWork net = new Proxy(new Real());
        net.browse();
    }
}

9.5 抽象类与接口的区别

区别抽象类接口
1关键字abstract classinterface
2组成构造方法 抽象方法 普通方法 static方法 常量 变量全局常量 抽象方法
3子类使用class 子类 extends 抽象类class 子类 implements 接口, 接口...
4关系抽象类可实现多个接口接口不能继承抽象类,却可以继承多个父接口
5权限可以使用各种权限只可使用public权限
6限制单继承局限没有单继承局限
7子类都必须要有子类,子类必须覆写全部的抽象方法
8实例化对象均依靠子类对象的向上转型进行对象的转化

10. 匿名内部类

匿名内部类是没有名字的内部类,其必须在抽象类或接口基础上才可以定义。

interface Message{
    public void print();
}

public class Hello{
    public static void main(String args[]){
        fun(new Message() {                  // 直接实例化接口对象,无需创建一个类
            @Override
            public void print() {            // 匿名内部类中覆写print()方法
                System.out.println("Hello");
            }
        });
    }

    public static void fun(Message msg){
        msg.print();
    }
}