Back
Featured image of post JavaOOP_02

JavaOOP_02

深入面向对象


  1. 面向对象三大特性
  2. static关键字详解
  3. 抽象类和接口
  4. 内部类及OOP实战

面向对象三大特性

封装

  • 我们在程序设计中要追求“高内聚,低耦合”。

    • 高内聚:就是类的内部数据操作细节由自己完成,不允许外部干涉
    • 仅暴露少量的方法给外部使用
  • 所以在设计时需要把一些数据与方法封装起来(数据的隐藏)

  • 属性私有,get/set调用

  • 作用

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

    Student类

    package com.oop.demo02;
    //学生类
    public class Student {
    
       private String name;
       private int age;
       private String sex;
    
        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 String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    }
    

    Test类

    package com.oop.demo02;
    //一个项目只能有一个main方法
    public class Test {
        public static void main(String[] args) {
            //new 实例化一个对象
            Student s1 = new Student();
            s1.setName("成志恒");
            s1.setAge(21);
            s1.setSex("男");
            System.out.println(s1.getName()+" "+s1.getAge()+" "+s1.getSex());
        }
    }
    

    image7

继承

  • 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。

  • JAVA中类只有单继承,没有多继承

  • 在java中,所有类都默认直接或者间接继承Object类

    继承使用关键字extends来表示,代码示例如下

    Person类

    package com.oop.demo03;
    
    public class Person {
        public int money = 10000;
        public String name = "mayun";
    }
    

    Person类为父类,只定义了两个属性

    Student类

    package com.oop.demo03;
    
    public class Student extends Person{
        public void print(){
            System.out.println(this.money+" "+this.name);
        }
    }
    

    Student类为子类,继承了父类的属性与方法

    Test类

    package com.oop.demo03;
    
    public class Test {
        public static void main(String[] args) {
            Student student = new Student();
            student.print();
        }
    }
    

    结果:

    image8

    由此可见,在Java中通过extends实现继承关系,而子类可以使用父类中的属性与方法(私有的不能调用)。

  • 在继承中,当子类中有与父类相同的属性或方法时,可以使用super关键字来调用父类的属性或方法

  • super 可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父类。

    代码示例:

    Person类

    package com.oop.demo03;
    
    public class Person {
        public int money = 10000;
        public String name = "Person";
    
        public void print(){
            System.out.println("Person调用了");
        }
    }
    

    Student类

    package com.oop.demo03;
    
    public class Student extends Person{
        public int money = 50000;
        public String name = "Student";
        public void print(){
            System.out.println("Student调用了");
        }
        public void test(String name){
            System.out.println(name);
            System.out.println(this.name);
            System.out.println(super.name);
        }
        public void test1(){
            print();//子类的方法
            this.print();//子类的方法
            super.print();//父类的方法
        }
    }
    

    Test

    package com.oop.demo03;
    
    public class Test {
        public static void main(String[] args) {
            Student student = new Student();
            student.test("成志恒");
            System.out.println();
            student.test1();
        }
    
    }
    

    运行结果:

    image9

    可以看到,this调用的是Student类中本身的值,super调用了Person类中的值。方法亦如此

  • super调用构造器

    Person类

    package com.oop.demo03;
    
    public class Person {
        public Person(){
            System.out.println("Person无参执行了");
        }
    }
    

    Student类

    package com.oop.demo03;
    
    public class Student extends Person{
        public Student(){
            System.out.println("Student无参执行了");
        }
    }
    
    

    Test

    package com.oop.demo03;
    
    public class Test {
        public static void main(String[] args) {
            Student student = new Student();
        }
    
    }
    

    image10

    由此可见在Student类中的无参构造器默认调用了Person类中的无参构造器,即隐藏使用了super()方法。

    需要注意的是,super()方法必须要在子类构造器的第一行,否则系统会报错

    image11

  • super的注意点

    • super调用父类的构造方法,必须在构造方法的第一个
    • super必须只能出现在子类的方法或者构造方法中
    • super与this不能同时调用构造方法
  • super与this的对比

    • 代表的对象不同

      this:本身调用者这个对象

      super:代表父类对象的应用

    • 前提

      this:没有继承也可以使用

      super:只能在继承条件才可以使用

    • 构造方法

      this():本类的构造

      super():父类的构造

  • 方法的重写(父类的功能,子类不一定需要,所以要重写)

    • 需要有继承关系,子类重写父类的方法,与属性无关
    • 重写只跟非静态方法有关,方法名必须相同
    • 参数列表必须相同
    • 子类的方法必须要和父类的一致,方法体不同
    • IDEA快捷键:Alt+Insert :override;

    代码:

    父类B

    package com.oop.demo03;
    
    public class B {
        public static void test1(){
            System.out.println("B==>test");
        }
        public void test2(){
            System.out.println("B==>test");
        }
    }
    

    子类A

    package com.oop.demo03;
    
    public class A extends B {
        public static void test1(){
            System.out.println("A==>test");
        }
        @Override//注解(重写用)
        public void test2() {
            System.out.println("A==>test");
        }
    }
    

    Test

    package com.oop.demo03;
    
    public class Test {
        public static void main(String[] args) {
            A a = new A();
            //父类的引用指向了子类
            B b = new A();
            a.test1();
            b.test1();
            System.out.println("==============");
            a.test2();//子类重写了父类的方法
            b.test2();
    
        }
    
    }
    

    image12

  • 静态方法和非静态方法的区别

    • 静态方法:方法的调用只与左边定义的数据类型有关
    • 非静态:重写

多态

  • 即同一方法可以根据发送对象的不同而采用多种不同的行为方式

  • 一个对象的实际类型是确定的,但可以指向对象的引用类型有很多

  • 对象能执行哪些方法,主要看左边的类型,与右边关系不大

  • 多态存在的条件

    • 有继承关系
    • 子类重写父类的方法
    • 父类引用子类对象

    代码示例

    Person类

    package com.oop.demo04;
    
    public class Person {
        public void run(){
            System.out.println("run");
        }
    }
    

    Student类

    package com.oop.demo04;
    
    public class Student extends Person{
    
    }
    

    Test

    package com.oop.demo04;
    
    public class Test {
        public static void main(String[] args) {
            //一个对象的实际类型是可以确定的
            //new Student
            //new Person
    
            //但可以指向的引用类型就不确定了:父类的引用指向子类
            Student s1 = new Student();
            Person s2 = new Student();
            Object s3 = new Student();
    
            s1.run();
            s2.run();
    
        }
    }
    

    image13

    可以知道虽然s1,s2,s3的对象都是Student,但是它可以有不同的父类的引用,这就是方法的多态。

    如果子类重写了父类的方法,则执行子类的方法

    在Studunt类中重写run方法

    package com.oop.demo04;
    
    public class Student extends Person{
        @Override
        public void run() {
            System.out.println("son run");
        }
    }
    
    

    运行结果:

    image14


    假如在子类中写一个独有的方法,s2可以调用吗?

    Student类

    package com.oop.demo04;
    
    public class Student extends Person{
        @Override
        public void run() {
            System.out.println("son run");
        }
        public void eat(){
            System.out.println("eat");
        }
    }
    
    

    在Student类中加了一个eat方法

    如果使用Test类中的s2调用这个方法,系统会报错

    image15

    所以父类可以指向子类,但是不能调用子类独有的方法

  • 多态的注意事项:

    • 多态是方法的多态,属性没有多态性
    • 父类和子类需要有联系,不然会有类型转换异常(ClassCastException)
  • instanceof 是 Java 的一个二元操作符,类似于 ==,>,< 等操作符。

  • instanceof 是 Java 的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型。

    package com.oop.demo05;
    
    public class Test {
        public static void main(String[] args) {
    
            //Object > String
            //Object > Person > Student
            //Object > Person > Teacher
            Object object = new Student();
    
            System.out.println(object instanceof Student);
            System.out.println(object instanceof Person);
            System.out.println(object instanceof Object);
            System.out.println(object instanceof String);
            System.out.println(object instanceof Teacher);
        }
    
    }
    

    image16

​ 需要注意的是若比较的两个类毫无联系,编译器会报错

image17

  • 类型转换

    • 父类引用指向子类的对象
    • 把子类转换为父类:向上转型
    • 把父类转换为子类:向下转型,强制转换
    package com.oop.demo05;
    
    public class Test {
        public static void main(String[] args) {
            Student student = new Student();
            student.run();//子类能直接调用父类的方法
    
            Person person = student;
            ((Student)person).eat();//父类调用子类的方法需要强制转换
        }
    
    }
    

    image18

Static关键字详解

  • static标注的属性或方法为静态属性或方法。

  • static(静态)方法只会在类加载的时候执行一次。

    package com.oop.demo06;
    
    public class Person {
        //先与构造方法执行,可以用来定义常量
        {
            System.out.println("匿名代码块");
        }
        //最先执行,但只执行一次
        static {
            System.out.println("静态代码块");
        }
        //最后执行
        Person(){
            System.out.println("构造方法");
        }
    
        public static void main(String[] args) {
            Person person = new Person();
            System.out.println("================");
            Person person1 = new Person();
        }
    }
    

    image19

  • static关键字还可以用来静态导入包

    正常来说要使用Math类的方法每一次都需要在方法前面加"Math."

    System.out.println(Math.random());
    

    否则会报错

    image20

    但是如果通过static导入包的话,就可以直接使用了

    package com.oop;
    
    import static java.lang.Math.random;
    public class Tset {
        public static void main(String[] args) {
            System.out.println(random());
        }
    }
    

抽象类和接口

抽象类

  • abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法,如果修饰类,那么该类就是抽象类

    package com.oop.demo08;
    //抽象类
    public abstract class Action {
        //抽象方法
        public abstract void run();
    
    }
    
  • 抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类

    package com.oop.demo08;
    
    public abstract class Action {
        public abstract void run();
        public void go(){
            System.out.println("go");
        }
    }
    

    image21

  • 抽象类不能new 只能靠子类去实现它

    image22

  • 抽象类存在的意义:在一些复杂的项目中,把公有属性抽象出来,再使用时只需要继承这个抽象类即可,提高开发效率。

接口

  • 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是…则必须能…”的思想。

  • 接口的本质是契约。

  • 接口中的所有定义的方法都是public abstract的;属性为常量。

  • 接口定义的关键字为interface,接口都需要有实现类

    接口UserService

    package com.oop.demo09;
    
    public interface UserService {
        void add(String name);
        void delete(String name);
        void update(String name);
        void query(String name);
    }
    

    实现类UserServiceImp

    package com.oop.demo09;
    //实现了接口的类就必须要实现接口中的所有方法
    public class UserServiceImp implements UserService{
    
        @Override
        public void add(String name) {
    
        }
    
        @Override
        public void delete(String name) {
    
        }
    
        @Override
        public void update(String name) {
    
        }
    
        @Override
        public void query(String name) {
    
        }
    }
    
  • 利用接口可以实现多继承!

    接口TimeService

    package com.oop.demo09;
    
    import java.sql.Time;
    
    public interface TimeService {
        Time timer();
    }
    

    接口RunService

    package com.oop.demo09;
    
    public interface RunService {
        void run();
    }
    

    实现类TestImp

    package com.oop.demo09;
    
    import java.sql.Time;
    
    public class TestImp implements TimeService,RunService{
        @Override
        public void run() {
    
        }
    
        @Override
        public Time timer() {
            return null;
        }
    }
    

内部类

  • 内部类就是在一个类的内部再定义一个类,详解见内部类解析
    • 成员内部类
    • 静态内部类
    • 局部内部类
    • 匿名内部类
Licensed under CC BY-NC-SA 4.0
Built with Hugo
Theme Stack designed by Jimmy