面向对象编程

目录

面向对象编程

对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,需要用面向对象的思路来分析整个系统。在微观上操作时,仍是使用面向过程进行处理。

面向对象编程OOP

面向对象的本质:以类的方式组织代码,以对象的形式封装数据。

三大特征:

  • 封装
  • 继承
  • 多态

方法的定义:

  • 修饰符
  • 返回类型(和return相对应)
  • 方法名
  • 参数
  • 异常

方法的调用:

  • 静态方法
  • 非静态方法
  • 形参和实参
  • 值传递和引用传递
  • this关键字
package com.oop.demo;

public class Demo1 {

    public static void main(String[] args) {
        //方法一
        Student student = new Student();
        student.say();
        //方法二
        new Student().say();

        int a = 1;
        System.out.println(a);
        c(a);
        System.out.println(a);

    }

    //和类一起加载
    public static void a() {

    }
    //类实例化后才存在
    public void b() {

    }
    //值传递
    public static void c(int a) {
        a = 10;
    }

}

Studen.java

package com.oop.demo;

public class Student {
    //非静态方法
    public void say() {
        System.out.println("hello");
    }
}

引用传递

package com.oop.demo;

public class Demo2 {
    //引用传递
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.name);
        change(person);
        System.out.println(person.name);
    }

    public static void change(Person person) {
        person.name = "abc";
    }

}

class Person {
    String name;
}

类和对象

类是一种抽象的数据类型,是对一类事物的描述,不代表某一具体事物

对象是对抽象概念的具体实例

使用new关键字来创建对象,进行分配内存空间,进行默认初始化,以及对类中构造器进行调用。

Student.java

package com.oop.demo2;

public class Student {
    //属性:字段
    String name;
    int age;

    //方法
    public void study() {
        System.out.println(this.name + "在学习");
    }

}

Application.java

package com.oop.demo2;

//一个项目应该只存在一个main方法
public class Application {
    public static void main(String[] args) {
        //类是抽象的,需要实例化
        //student为Student的一个具体实例
        Student student = new Student();
        student.name = "Mk";
        student.age = 20;

        System.out.println(student.name);
        System.out.println(student.age);
        student.study();
    }
}

小结:

  1. 类是一个模板,对象是一个具体实例

  2. 方法的定义和调用

  3. 对象是通过引用来操作的:栈--->堆

  4. 属性默认初始化

  5. 使用new关键字来创建对象,注意构造器的使用

  6. 类:

    静态的属性:属性

    动态的行为:方法

构造器

使用new时,本质是在调用构造器(构造方法),构造器一般用于调用初始化值

构造器(构造方法):

  1. 与类名同名
  2. 没有返回值

作用:

  1. new本质在调用构造器
  2. 初始化值

注意:

  • 一旦定义了有参构造,无参构造必须显式定义

Person.java

package com.oop.demo2;

public class Person {
    String name;

    //IDEA中的快捷键 alt+insert产生构造方法
    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }
}

Application.java

package com.oop.demo2;

//一个项目应该只存在一个main方法
public class Application {
    public static void main(String[] args) {

        Person person = new Person();
        System.out.println(person.name);
        Person person1 = new Person("Mk");
        System.out.println(person1.name);

    }
}

创建对象时的内存分析

Pet.java

package com.oop.demo3;

public class Pet {
    String name;
    int age;

    public void shout() {
        System.out.println("汪汪汪");
    }
}

Application.java

package com.oop.demo3;

public class Application {
    public static void main(String[] args) {
        Pet dog = new Pet();
        dog.name = "abcd";
        dog.age = 1;
        dog.shout();
    }
}

面向对象编程

封装

程序设计追求“高内聚,低耦合”

  • 高内聚:类的内部数据操作自己完成,不允许外部干涉
  • 低耦合:仅暴露少量方法给外部使用

封装(隐藏数据):禁止直接访问一个对象中实际的数据,而是通过操作接口

属性私有,get/set方法

封装作用:

  1. 提高程序安全性,保护数据
  2. 隐藏代码实现的细节
  3. 统一接口
  4. 系统可维护增加

Student.java

package com.oop.demo4;

public class Student {
    //属性私有
    private String name;//名字
    private int id;//学号
    private String sex;//性别
    private int age;//年龄

    //提供可操作私有属性的方法
    //提供public的get、set方法,alt+insert快捷键
    public String getName() {
        return this.name;
    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getSex() {
        return sex;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age > 120 || age < 0) {
            this.age = 1;
        } else {
            this.age = age;
        }
    }
}

Application.java

package com.oop.demo4;

public class Application {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setName("Mk");
        s1.setAge(12);
        System.out.println(s1.getName());
    }
}

继承

关键字:extends

Java中为单继承,无多继承。继承是类与类之间的关系,私有的private无法被继承

在Java中,所有类都直接或间接继承自Object类

IDEA中,ctrl+h可查看继承结构

Person.java

package com.oop.demo5;

public class Person {
    private int money;

    public void say () {
        System.out.println("hello");
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }
}

Student.java

package com.oop.demo5;

public class Student extends Person {

}

Application.java

package com.oop.demo5;

public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        student.say();

    }
}

super

  1. 调用父类构造方法时,需在子类构造方法的第一个,先调用父类的构造器,后调用子类的构造器
  2. super只能在方法或构造方法中
  3. super和this不能同时调用构造方法

super和this区别:

  1. 代表对象不同:
    super代表父类

    ​ this代表本类

  2. 前提:

    ​ super仅在继承下使用

    ​ this无继承也可使用

  3. 构造方法

    ​ this():本类构造

    ​ super():父类的构造

Person.java

package com.oop.demo5;

public class Person {
    //无参构造

    public Person() {
        System.out.println("Person无参构造");
    }

    protected String name = "a";
    
}

Student.java

package com.oop.demo5;

public class Student extends Person {
    private String name = "b";


    public Student() {
        //默认调用了父类的无参构造
        //super()被隐藏,先调用父类的构造器,后调用子类的构造器
        System.out.println("Student的无参构造");
    }

    public void test() {
        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);
    }
}

Application.java

package com.oop.demo5;

public class Application {
    public static void main(String[] args) {
        Student student = new Student();
    }
}

方法重写

重写是方法的重写,和属性无关

IDEA快捷键:alt+insert :-->Override

重写:需要有继承关系,子类重写父类的方法

  1. 方法名相同
  2. 参数列表相同
  3. 修饰符的范围仅能扩大,不能缩小。public > protected > default > private
  4. 抛出异常时范围可缩小

B.java

package com.oop.demo6;

public class B {
    public static void test () {
        System.out.println("B>test");
    }
}

A.java

package com.oop.demo6;

public class A extends B {

    public static void test() {
        System.out.println("A>test");
    }
}

Application.java

package com.oop.demo6;

public class Application {
    public static void main(String[] args) {
        //静态方法:方法的调用仅和定义的类型有关
        A a = new A();
        a.test();

        //父类的调用指向了子类
        B b = new A();
        b.test();
    }
}

结果:

面向对象编程

B.java

package com.oop.demo6;

public class B {
    public void test () {
        System.out.println("B>test");
    }
}

A.java

package com.oop.demo6;

public class A extends B {

    //Override:重写
    @Override //注解 alt+insert
    public void test() {
        System.out.println("A>test");
    }
}

Application.java

package com.oop.demo6;

public class Application {
    public static void main(String[] args) {
        //静态方法:方法的调用仅和定义的类型有关
        //非静态方法:重写
        A a = new A();
        a.test();

        //父类的调用指向了子类
        B b = new A();
        b.test();
    }
}

结果:

面向对象编程

多态

利用多态实现可扩展性,动态编译

对象能执行哪些方法,主要看引用类型,和new的关系不大

多态存在条件:

  1. 有继承关系
  2. 子类重写父类
  3. 父类引用指向子类对象

多态小结:

  1. 多态是方法的多态,和属性无关
  2. 父类子类可进行强制转换
  3. 父类引用指向子类时,父类不能调用子类独有的方法
  • static方法不能重写

  • final为常量

  • private方法私有,不能重写

Person.java

package com.oop.demo7;

public class Person {
    public void run() {
        System.out.println("Person");
    }

}

Student.java

package com.oop.demo7;

public class Student extends Person {
    @Override
    public void run() {
        System.out.println("Student");
    }

    public void eat() {
        System.out.println("eat");
    }
}

Application.java

package com.oop.demo7;

public class Application {
    public static void main(String[] args) {
        //一个对象的实际类型确定后(new),引用时可指向自身的父类

        //s1能调用自己的方法和重写的父类的方法
        Student s1 = new Student();
        //s2不能调用子类独有的方法,父类引用指向子类
        Person s2 = new Student();
        Object s3 = new Student();

        s1.run();
        s2.run();

        //s2.eat();不能调用子类独有的方法
        ((Student) s2).eat();//强制转换
    }
}

结果:

面向对象编程

instanceof和类型转换

父类和子类,类似于基本数据类型中的高和低数据关系(double和int)

低转高时,自动转换;高转低时需要强制转换

Application.java

package com.oop.demo8;

public class Application {
    public static void main(String[] args) {
        //instanceof
        Object object = new Student();

        System.out.println(object instanceof Object);
        System.out.println(object instanceof Person);
        System.out.println(object instanceof Student);
        System.out.println(object instanceof String);

        //类型转换
        //子类转换为父类会丢失自己独有的方法
        //高                   低
        Person student = new Student();
        //强制转换
        Person p = new Person();
        Student s = (Student) p;
        Student student1 = new Student();
        //子类转换为父类时自动转换
        Person person = student1;


    }
}

static

非静态方法可调用静态方法,静态方法可调用静态方法,静态方法不可调用非静态方法

Person.java

package com.oop.demo9;

public class Person {
    
    {//第二次执行,可用来赋初始值
        System.out.println("匿名代码块");
    }
    static { //只执行一次,第一次执行
        System.out.println("静态代码块");
    }
    public Person() {
        System.out.println("构造方法");
    }
    
}

Application.java

package com.oop;

import com.oop.demo9.Person;

public class Application {
    //一个项目有一个主方法main
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println("==========================");
        Person person1 = new Person();
    }
}

结果:

面向对象编程

静态导入包:

package com.oop.demo9;

//静态导入包
import static java.lang.Math.random;

public class Test {
    public static void main(String[] args) {
        System.out.println(Math.random());
        System.out.println(random());
    }
}

抽象类

关键字:abstract

特点:

  1. 不能进行new实例化,仅能用子类来实现
  2. 抽象类中可以由抽象方法,也可有普通方法
  3. 抽象方法仅能存在在抽象类中

抽象类也有抽象方法

Action.java

package com.oop.demo10;

//抽象类,也可以有普通的方法
public abstract class Action {

    public Action () {
        System.out.println("Action");
    }

    //用在方法上,进行约束,无方法实现
    public abstract void doSomething();

    public void run () {
		System.out.println("run");
    }

}

A.java

package com.oop.demo10;

//抽象类中的抽象方法必须全部实现
public class A extends Action {

    @Override
    public void doSomething() {

    }
}

Application.java

package com.oop;

import com.oop.demo10.A;

public class Application {
    public static void main(String[] args) {
        A a = new A();
        a.run();
    }

}

面向对象编程

接口

  • 普通类:只要具体实现
  • 抽象类:具体实现和抽象方法
  • 接口:只有规范,实现约束和实现分离

接口关键字:interface、implements

作用:

  1. 约束
  2. 定义方法来让不同人实现
  3. 方法为public abstract
  4. 属性为public static final
  5. 接口不能被实例化,接口中没有构造方法
  6. 可以用implements实现多个接口
  7. 必须重写接口中的方法

TimeService.java

package com.oop.demo11;

public interface TimeService {
    void timer();
}

UserService.java

package com.oop.demo11;

//接口都需要有实现类
public interface UserService {
    //接口中所有方法的定义都是public abstract

    void add(String name);
    void delete(String name);
    void update(String name);
    void query(String name);

    //接口中的属性 public static final
    int a = 3;
}

UserServiceImp.java

package com.oop.demo11;

public class UserServiceImp implements UserService, TimeService{
    @Override
    public void add(String name) {

    }

    @Override
    public void delete(String name) {

    }

    @Override
    public void update(String name) {

    }

    @Override
    public void query(String name) {

    }

    @Override
    public void timer() {

    }
}

内部类

Outer.java

package com.oop.demo12;

public class Outer {
    private int id = 1;

    public void out () {
        System.out.println("外部类");
    }

    public class Inner{
        public void in () {
            System.out.println("内部类");
        }
        //用内部类访问外部类的私有属性、方法
        public void getId () {
            System.out.println(id);
        }

    }
}

Application.java

package com.oop;

import com.oop.demo12.Outer;

public class Application {
    public static void main(String[] args) {
        Outer outer = new Outer();

        //通过外部类来实例化内部类
        Outer.Inner inner = outer.new Inner();
        inner.in();
        inner.getId();

    }

}

局部内部类

package com.oop.demo12;

public class Outer2 {

    public void method () {
        //局部内部类
        class Inner {
            public void in () {
                
            }
        }
    }
}

匿名内部类

package com.oop.demo12;

public class Test {
    //没有名字初始化类,不用将名字保存在变量中
    public static void main(String[] args) {
        new Apple().eat();

        /*
        UserService userService = new UserService() {
            @Override
            public void hello() {

            }
        };
        */
        new UserService() {
            //匿名内部类
            @Override
            public void hello() {
                
            }
        }
    }
}

class Apple {
    public void eat () {
        System.out.println("Apple");
    }
}

interface UserService {
    void hello();
}
上一篇:三篇讨论 ECS 的文章


下一篇:sv 从0到1 oop