Java面向对象


封装

将某些属性和实现细节隐藏在类内部,不允许外部程序直接访问,要访问该类的隐藏数据,必须通过指定的方式进行。

将不需要对外提供的内容隐藏,提供公共方法对其进行访问。

  • 通过使用private对属性进行私有化;
  • public set 变量名()方法,对属性进行赋值;
  • public get 变量名()方法,用于获取属性的值;

定义Person类

public class Person {
    // 定义私有属性
    private String name;
    private int age;

    // 定义构造方法
    public Person() {
    }

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

    public String getName() {
        return name;
    }

    // 定义setter和getter
    public void setName(String name) {
        if (!name.isEmpty()) {
            this.name = name;
        }
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age > 0) {
            this.age = age;
        } else {
            this.age = 18;
        }
    }

    // 定义showMe方法
    public void show() {
        System.out.println("我是" + name + ",今年" + age + "岁了。");
    }
}

定义测试类

public class PersonTest {
    public static void main(String[] args) {
        Person p1 = new Person("laobai", 18);
        p1.show();

        p1.setName("AILynn");
        p1.setAge(-1);
        p1.show();
    }
}

执行结果:

我是laobai,今年18岁了。
我是AILynn,今年18岁了。

访问权限

访问范围 public protected default private
同一个类中
同一个包中
子类
不同包中

static关键字

static修饰的变量,被称为静态变量,也叫类变量;由static修饰的方法,被称为静态方法,也叫类方法。可以通过类名.变量名类名.方法名来访问。

继承

子类继承父类的属性和行为,使得子类对象可以直接具有与父类相同的属性、相同的行为。子类可以直接访问父类的非私有的属性和行为。

以上面封装中的Person类为父类,写Student子类继承Person类

public class Student extends Person{

}

Student类使用extends关键字继承了Person类,没有写其他代码,但已经拥有了Person类的属性和方法。

public class StudentTest {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setName("小明");
        s1.setAge(12);
        s1.showMe();
    }
}

执行结果:

我是小明,今年12岁了。

在Student类中增加身高属性,并重写父类的show()方法

package test02;

public class Student extends Person {
    private int height; // 身高厘米,只要整数部分

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public void show() {
        super.show();
        System.out.println("我在的身高是:" + height + "cm");
    }
}

修改StudentTest.java

package test02;

public class StudentTest {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setName("小明");
        s1.setAge(18);
        s1.show();
        s1.setHeight(175);
        s1.show();
    }
}

执行结果:

我是小明,今年18岁了。
我在的身高是:0cm
我是小明,今年18岁了。
我在的身高是:175cm

通过super关键字调用父类的属性和方法。super必须写在方法的第一行。

方法重写与方法重载:

  • 方法重写,发生在子类和父类之间,子类和父类的方法完全相同,方法名、返回值类型、参数列表均形同;
  • 方法重载,发生在同一个类中,或子类中,方法名相同,参数不同,参数个数不同,或参数类型不同。

方法重写可以使用@Override注解来修饰

@Override
public void show() {
    super.show();
    System.out.println("我的身高是:" + height + "cm");
}

final修饰变量为常量;修饰方法,方法无法被重写;修饰类,类不能被继承。

多态

多态是指同一个行为可以有多个不同表现形式。也就是在父类中定义的属性和方法,在子类继承后,可以有不同的数据类型或表现不同的行为。这可以使得同一个属性和方法,在父类及其各个子类中,可能有不同的表现或含义。

多态分为编译时多态和运行时多态。编译时多态主要是通过方法重载overload来实现;运行时多态主要通过方法的重写override来实现。编译时取决于父类,运行时取决于子类。

新建教师类,私有属性工龄seniority

package test02;

public class Teacher extends Person {
    private int seniority; // 工龄

    public int getSeniority() {
        return seniority;
    }

    public void setSeniority(int seniority) {
        this.seniority = seniority;
    }

    @Override
    public void show() {
        super.show();
        System.out.println("我的工龄是" + seniority + "年.");
    }
}

测试类

package test02;

public class Test {
    public static void main(String[] args) {
        // 向上转型
        Person stu1 = new Student();
        Person tea1 = new Teacher();
        Person per1 = new Person();

        stu1.setName("AILynn");
        stu1.setAge(16);
        stu1.show();
        tea1.setName("PLScript");
        tea1.setAge(26);
        tea1.show();
        per1.setName("Laobai");
        per1.setAge(28);
        per1.show();

        System.out.println("--------------------");
        // 向下转型
        Student stu2 = (Student)stu1;
        stu2.setHeight(175);
        stu2.show();
        Teacher tea2 = (Teacher)tea1;
        tea2.setSeniority(20);
        tea2.show();
    }
}

执行结果:

我是AILynn,今年16岁了。
我的身高是:0cm
我是PLScript,今年26岁了。
我的工龄是0年.
我是Laobai,今年28岁了。
--------------------
我是AILynn,今年16岁了。
我的身高是:175cm
我是PLScript,今年26岁了。
我的工龄是20年.

抽象类

抽象类是一种不能被实例化的类,其目的是为了被其他类继承并实现其抽象方法。抽象方法是一种没有实现的方法,只有定义,需要在子类中被实现。抽象类可以包含非抽象方法和属性,但至少要有一个抽象方法。抽象类使用abstract关键字修饰,而抽象方法同样使用abstract关键字来修饰。

  • 抽象类不能被实例化,只能被继承;
  • 抽象类可以包含抽象方法和非抽象方法;
  • 抽象方法只有声明,没有实现;
  • 抽象方法必须被子类实现;
  • 抽象类可以被用来定义一些通用的方法和属性,让子类继承并实现;

新建人类抽象类

public abstract class Person {

    // 有抽象方法的类,必须是抽象类;
    // 抽象类中可以没有抽象方法
    // 抽象类不能实例化对象,必须被子类继承

    public abstract void eat();

    public void drink(){
        System.out.println("喝水");
    }
}

工人类并实现抽象方法

import test03.Person;

// 子类继承抽象类之后,必须要重写父类的抽象方法 或 子类也是抽象类,由子类的子类重写抽象方法
public class Worker extends Person {
    @Override
    public void eat() {
        System.out.println("一日三餐");
    }
}

测试类

public class TestWorker {
    public static void main(String[] args) {
        Worker worker1 = new Worker();
        worker1.eat();
    }
}

接口

接口在java中是一个抽象类型,是抽象方法的集合。接口以interface来声明,一个类通过继承接口的方式从而来继承接口的抽象方法。接口并不是类,类描述对象的属性和方法。接口则包含类要实现的方法。接口无法被实例化,但可以被实现。一个实现接口的类,必须实现接口内所有的抽象方法,否则就必须声明为抽象类。一个类可以实现2个接口,也可以继承和实现接口同时使用。

新建一个人类的接口

package test04;

public interface Person {

    // 抽象方法
    // 默认添加public abstract修饰符
    void eat();

    void talk();

    // 静态常量,不推荐使用
    // 默认添加public static final修饰符
    String name = null;

    // 默认方法
    // 子类可以直接使用默认方法,也可以根据需要重写默认方法。
    default void breathe(){
        System.out.println("呼吸新鲜空气!");
    }

    // 静态方法
    // 不能被继承,通过接口名调用。
    static void declaration(){
        System.out.println("生而无畏,战至终章!");
    }
}

另写一个语言的接口

package test04;

public interface Language {
    void foreign();
}

写个工人类实现上面两个接口

package test04;

// 非抽象类实现接口,必须重写所有的抽象方法
public class Worker implements Person, Language{
    @Override
    public void eat() {
        System.out.println("一日三餐");
    }

    @Override
    public void talk() {
        System.out.println("谈笑风生");
    }

    @Override
    public void foreign() {
        System.out.println("Speaking English");
    }
}

测试类

package test04;

public class Test {
    public static void main(String[] args) {
        Worker worker1 = new Worker();
        worker1.eat();
        worker1.talk();

        worker1.breathe();
        Person.declaration();

        worker1.foreign();
    }
}

执行结果:

一日三餐
谈笑风生
呼吸新鲜空气!
生而无畏,战至终章!
Speaking English

内部类

在一个类的内部定义一个内部类

public class Apple {    // 外部类 Apple
    private String brand = "Apple"; //  品牌名苹果


    // 成员内部类
    // 内部类可以直接访问外部类的成员,包括私有成员
    // 外部类访问内部类成员,必须创建内部类对象
    // 外部类内部,实例化内部类: 内部类 对象变量名 = new 内部类()
    // 外部类外部,实例化内部类:外部类.内部类 对象变量名 = new 外部类().new 内部类
    class Phone{
        private String model = "iphone 15";  // 型号
        public void show(){
            System.out.println("品牌是:" + brand);
        }
    }

    public void produce() {
        // 若要访问内部类,需定义成员内部类对象
        Phone phone = new Phone();
        System.out.println(phone.model);
        phone.show();
    }
}

测试内部类

public class AppleTest {
    public static void main(String[] args) {
        Apple apple = new Apple();
        apple.produce();

        Apple.Phone phone = new Apple().new Phone();
        phone.show();
    }
}

执行结果:

iphone 15
品牌是:Apple
品牌是:Apple

成员内部类

  • 内部类可以直接访问外部类的成员,包括私有成员
  • 外部类访问内部类成员,必须创建内部类对象
  • 外部类内部,实例化内部类: 内部类 对象变量名 = new 内部类()
  • 外部类外部,实例化内部类:外部类.内部类 对象变量名 = new 外部类().new 内部类

静态内部类:

  • 静态内部类,不能直接访问外部类的非静态成员;
  • 静态内部类,可以直接范围外部类的静态成员;
  • 外部类的内部,访问静态内部类中的静态成员:静态类名.静态成员;
  • 外部类的外部,访问静态内部类中的静态成员:外部类名.静态类名.静态成员;
  • 外部类的内部,实例化静态内部类:内部类 对象名 = new 内部类();
  • 外部类的外部,实例化静态内部类:外部类.内部类 对象名 = new 外部类.内部类();
  • 访问内部类的非静态成员,先实例化静态内部类,通过对象访问。

文章作者: 老百
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 老百 !
  目录