java面向对象编程

1. 1、什么是面向对象

c58d0f4ea6fc57ac024d00afed67827d_MD5.png

本质:以类的方式组织代码,以对象的组织(封装)数据

三大特性:封装、继承、多态

2. 2、面向对象

静态方法

package OOP;

public class Demo02 {
    //静态方法 static
    public static void main(String[] args) {
        Student.say();
    }

    //非静态方法
}

public class Student {
    public static void say(){
        System.out.println("Hello World");
    }

}

34883412e9893e4993af3f182678e252_MD5.png

非静态方法,需要实例化 学生这个类

package OOP;

public class Demo02 {
    //静态方法 static
    //非静态方法
    public static void main(String[] args) {
        Student student = new Student();
        student.say();
    }
}

37509b6adf9c1294979ffbd3c7bd212b_MD5.png

3. 3、创建对象与初始化对象

Application.java

package OOP.demo05;

public class Application {
    public static void main(String[] args) {
        Student student =new Student();//实例化对象
        Student xiaoming =new Student();
        Student xiaohong =new Student();

        xiaoming.name="小明";
        xiaoming.age=18;
        System.out.println(xiaoming.name);
        System.out.println(xiaoming.age);
    }
}

Student.java

package OOP.demo05;
//学生类
public class Student {
    //属性:字段
    String name;
    int age;
    //方法:函数
    public void study(){
        System.out.println(this.name+"正在学习");
    }
}

4. 4、构造器详解

构造器也叫构造方法

一个类即使什么都不写 也会存在一个方法(构造方法)

构造方法满足 1、与类名相同 2、无返回值

4.1. 构造器的作用

1、使用new关键字,必须要有构造器

2、构造器一般用于初始化值

5. 5、内存分析

10871f223cef73c36b3d734214b7527d_MD5.png

6. 6、封装

白话:该露的露,该藏的藏

专业:我们程序设计要追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。

封装(数据的隐藏)

在定义一个对象的特性的时候,有必要决定这些特性的可见性,即哪些特性对外部是可见的,哪些特性用于表示内部状态。通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏

使用private 修饰需要封装的成员变量

private无法直接调用赋值

08e8b81de286f0db6957a1b20accd4d3_MD5.png

但可以用设置的公共方法对其进行操作

package OOP.demo06;

public class Student {
    private String name;
    private int age;
    private int id;
    private String sex;
    //提供一些方法用于对这些私有属性进行操作
    public String getName(){
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

赋值

package OOP.demo06;

public class Application {
    public static void main(String[] args) {
        Student xiaoming =new Student();
        xiaoming.setName("小明");
        System.out.println(xiaoming.getName());
    }
}

还可以用alt+insert 快速设置属性的 Get set方法

955fa808ee1b8cc551283d2218b15e93_MD5.png

6.1. 封装的意义 好处

1、提高程序的安全性,保护数据

2、隐藏代码的实现细节

3、统一接口

4、提高程序的可维护性

7. 7、继承

继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模
为什么需要继承?继承的作用? 第一好处:继承的本质在于抽象。类是对对象的抽象,继承是对某一批类的抽象。

第二好处:为了提高代码的复用性。

extands的意思是“扩展”。子类是父类的扩展。

定义‘人’类

package OOP.Demo07;

public class Person {
    String name;
    int age;
}

继承

package OOP.Demo07;

public class Student extends Person{
}

其中 Person为父类 ,Student为子类(派生类)

这里只能继承公有的 属性,方法

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

java中只有单继承 没有多继承(一个儿子只能有一个爹,但一个爹可以有多个儿子)

8. 8、继承-super

不管是显式还是隐式的父类的构造器,super语句一定要出现在子类构造器中第一行代码。所以this和super不可能同时使用它们调用构造器的功能,因为它们都要出现在第一行代码位置。

【super使用的注意的地方】

  1. 用super调用父类构造方法,必须是构造方法中的第一个语句。
  2. super只能出现在子类的方法或者构造方法中。
  3. super 和 this 不能够同时调用构造方法。(因为this也是在构造方法的第一个语句)

【super 和 this 的区别】

  1. 代表的事物不一样:
    1. this:代表所属方法的调用者对象
    2. super:代表父类对象的引用空间。
  2. 使用前提不一致:
    1. this:在非继承的条件下也可以使用。
    2. super:只能在继承的条件下才能使用。
  3. 调用构造方法:
    1. this:调用本类的构造方法。
    2. super:调用的父类的构造方法

9. 9、继承-方法重写

条件

  1. 方法重写只存在于子类和父类(包括直接父类和间接父类)之间。在同一个类中方法只能被重载,不能被重写.
  2. 静态方法不能重写
  3. 父类的静态方法不能被子类重写为非静态方法 //编译出错
  4. 父类的非静态方法不能被子类重写为静态方法;//编译出错
  5. 子类可以定义与父类的静态方法同名的静态方法(但是这个不是覆盖)
  6. 私有方法不能被子类重写,子类继承父类后,是不能直接访问父类中的私有方法的,那么就更谈不上重写了。

重写的语法

  1. 方法名必须相同
  2. 参数列表必须相同
  3. 访问控制修饰符可以被扩大,但是不能被缩小: public protected default private
  4. 抛出异常类型的范围可以被缩小,但是不能被扩大 ClassNotFoundException ---> Exception
  5. 返回类型可以相同,也可以不同,如果不同的话,子类重写后的方法返回类型必须是父类方法返回类型的子类型

10. 10、什么是多态

10.1. 多态的存在条件

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

注:多态是方法的多态,属性没有多态性

4c98b0f921956c66caf80c74861e6420_MD5.png

s2是父类Person的引用,其创建了一个Student 类的实例,这里由于父类中没有eat()方法,所以s2.eat()是无法成功的。
当父类中有eat方法时,如果子类没有重写方法,则会调用父类中的方法,重写则调用子类的方法

但是也可以通过强制转换来执行eat方法

22269f6fcb72e2245dd82e81bb7ad3fd_MD5.png

Application.java

package OOP.demo09;

public class Application {
    public static void main(String[] args) {
        //一个对象的实际类型是确定的
        // new Student();
        // new Person();
        //但可以指向的引用类型是不确定的

        Student s1 =new Student();
        //父类的引用指向子类的对象
        Person s2 =new Student();
//      但是不可以用子类的引用指向父类的对象
//      Student s3 =new Person();
        Object s4 =new Student();

        s1.run();
        s2.run();
        s1.eat();
//        s2.eat();
        ((Student)s2).eat();
    }
}

Student.java

package OOP.demo09;

public class Student extends Person {

    //重写父类run方法
    @Override
    public void run() {
        System.out.println("学生正在跑步");
    }
    public void eat(){
        System.out.println("学生正在吃饭");
    }
}

Person.java

package OOP.demo09;

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

}

10.2. 多态注意事项

  • 多态是方法的多态,属性没有多态
  • 父类与子类有联系, 类型转换异常 ClassCastException
  • 存在条件: 继承关系 执行了子类的方法,父类的引用指向子类对象

11. 11、instanceof 与 类型转换

11.1. instanceof : 可以判断一个对象是什么类型

这里创建了三个类,父类Person 子类1 Student 子类2 Teacher

package OOP.demo10;

public class Application {
    public static void main(String[] args) {
        Object object =new Student();
        //Object -> Person -> Student
        //Object -> Person -> Teacher
        //Object -> String
        System.out.println(object instanceof Student);//true
        System.out.println(object instanceof Person);//true
        System.out.println(object instanceof Object);//true
        System.out.println(object instanceof String);//false
        System.out.println(object instanceof Teacher);//false
        System.out.println("==================");
//Object -> Person -> Student
//Object -> Person -> Teacher
        Person person =new Student();
        System.out.println(person instanceof Student);//true
        System.out.println(person instanceof Person);//true
        System.out.println(person instanceof Object);//true
//      System.out.println(person instanceof String); 编译报错
        System.out.println(person instanceof Teacher);//false
        System.out.println("==================");

//Object -> Person -> Student
        Student student =new Student();
        System.out.println(student instanceof Student);//true
        System.out.println(student instanceof Person);//true
        System.out.println(student instanceof Object);//true
//      System.out.println(student instanceof String); 编译报错
//      System.out.println(student instanceof Teacher); 编译报错
    }
}

其中绿色的就是关系表,如果两者有关系(在一条关系链上) 那么就会返回true,

由于都是Student类的实例,则其主要关系链 就一定含有Student

true:二者在主要关系链上(**标粗绿色的**)

flase:二者不在主要关系链上,但存在另外的关系链(没有标粗绿色的

编译报错:二者无关系链

11.2. 强制类型转换

public class Application {
    public static void main(String[] args) {
    //   高                    低
        Person  student =new Student();
//        student.go(); 无法执行
        ((Student)student).go(); //强制类型转换为Student类型
    }
}
  • 父类引用指向子类对象
  • 把子类转换为父类,向上转型
  • 把父类转换为子列,向下转型,强制转换
  • 方便方法的调用,减少重复的代码,更加简洁

12. 12、 static关键词

  • static加在方法上 就是静态方法;加在属性上,就是静态属性

12.1. 非静态方法可以调用静态方法

public class Student {
    private static int age;//静态变量
    private double score;//非静态变量

    public static void main(String[] args) {
        go();
        //run(); 无法运行
    }
    public void run(){
        go();
    }
    public static void go(){
        System.out.println("go");
    }
}

静态方法会与类一起加载,但非静态方法不会,所以 run();编译错误

非静态方法run 调用了静态方法 go

12.2. 匿名代码块与静态代码块

public class Person {
    {
        //代码快(匿名代码块)
        System.out.println("匿名代码块");
    }

    static {
        //静态代码块
        System.out.println("静态代码块");
    }
}

12.3. 执行顺序

package OOP.demo11;

public class Person {
    {
        //代码快(匿名代码块)
        System.out.println("匿名代码块");
    }
    static {
        //静态代码块
        System.out.println("静态代码块");
    }
    public Person() {
        System.out.println("构造方法");
    }
    public static void main(String[] args) {
        Person person = new Person();
    }
}

输出

静态代码块
匿名代码块
构造方法

观察输出可以发现,先执行了静态代码块 然后执行匿名代码块 再执行构造方法

注:静态代码块只会执行一次

例子

package OOP.demo11;

public class Person {
    {
        //代码快(匿名代码块)
        System.out.println("匿名代码块");
    }

    static {
        //静态代码块
        System.out.println("静态代码块");
    }

    public Person() {
        System.out.println("构造方法");
    }

    public static void main(String[] args) {
        Person person1 = new Person();
        System.out.println("=================");
        Person person2 = new Person();
    }
}

输出

静态代码块
匿名代码块
构造方法
=================
匿名代码块
构造方法

可以发现输出第二次构造方法时,没有执行静态代码块

静态代码块只会在第一次执行时最开始运行

12.4. 静态导入包

如下代码

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

我希望直接使用 random() 而不用加上 Math.

则可以通过静态导入包实现

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

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

13. 13、抽象类

13.1. abstract 抽象类

public abstract class Action {

}

13.2. abstract 抽象方法

public abstract class Action {
    //约束~有人帮我们实现
    //abstract 抽象方法,只有方法名字,没有方法实现
    public abstract void doSomething();
}

当我们设置了抽象方法后,使用另外一个类继承这个类时,则

必须重写抽象方法 或者将子类也设置为抽象类

15358db2e69369b2c7c09ae71766c1df_MD5.png

13.3. 抽象类的特点

  1. 不能new这个抽象类,只能靠子类去实现他;约束!
  2. 抽象类中可以写普通的方法
  3. 抽象方法必须在抽象类中

13.4. 抽象的意义

  • 抽象出来,提高开发效率

14. 14、接口的实现与定义

14.1. 普通类 抽象类 接口

  • 普通类:只有具体实现
  • 抽象类:具体实现和规范(抽象方法)都有!
  • 接口:只有规范!

14.2. 接口的本质

  • 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是…则必须能…”的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。如果你好人,则必须干掉坏人;如果你是坏人,则必须欺负好人。
  • 接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。

14.3. 接口的定义与实现

用接口定义增删改查

public interface UserService {
    //接口中所有定义都是抽象的 public abstract
    void add();
    void delete();
    void update();
    void query();
}

只写了接口,还需要一个类来实现接口里面的方法,这里用到关键字implements

package OOP.demo13;
//类可以实现接口 用implements关键字
//对比抽象类 单继承 extends
public class UserServiceImpl implements UserService {
    @Override
    public void add() {

    }

    @Override
    public void delete() {

    }

    @Override
    public void update() {

    }

    @Override
    public void query() {

    }
}

实现了接口的类,就要重写接口中的方法

14.4. 实现多个接口的类(接口实现多继承)

除了UserService 接口

我们新建一个接口 取名TimeService

package OOP.demo13;

public interface TimeService {
    void timer();
}

我们可以在一个类里面实现多个接口

只需要将多个接口用逗号分开 并实现其方法即可

3a6eb24c8a0a5668de19eee051791751_MD5.png

14.5. 接口的作用

  1. 约束
  2. 定义一些方法,让不同的人实现
  3. 接口不能被实例化(接口中无构造方法)
  4. 可以用Implements 实现多个接口
  5. 必须要重写接口中的方法

15. 15、内部类

例子:A类中再定义一个B类 (套娃)

package OOP.demo14;

public class Outer {
    private  int id ;
    public void out(){
        System.out.println("outer");
    }
    class Inner{
        public void in(){
            System.out.println("inner");
        }
    }
}

15.1. 通过外部类调用内部类

public class Application {
    public static void main(String[] args) {
        //new
        Outer outer = new Outer();
        //通过外部类来实例化内部类
        Outer.Inner inner = outer.new Inner();
        inner.in();
    }
}

15.2. 获取外部类的私有属性

ebe79f7fd0d0c1cfd0ce1d073baaf476_MD5.png

一个java类中可以有多个class类,但只能有一个public class