嘚儿驾...

6_面向对象

1 什么是面向对象?

面向过程 & 面向对象

​ Java 的核心思想就是 OOP (OO object-oriented就是面向对象)

  • 面向过程思想
    • 步骤清晰简单,第一步做什么,第二步做什么...
    • 面向过程适合处理一些比较简单的问题
  • 面向对象思想
    • 物以类聚,分类的思维模式,思考问题,首先会想解决问题需要哪些分类,然后对这些分类进行单独思考。最后,再对某个分类下的细节进行面向对象过程的思索。
    • 面向对象适合处理复杂的问题,适合处理需要多人协作的问题!
  • 总结:对于描述复杂的事物,为了从宏观上把握,从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍需要面向对象过程的思路去处理。

什么是面向对象

  • 面向对象编程(OOP)
  • 面向对象的本质就是:以类的方式组织代码,以对象的形式组织(封装)数据。
  • *抽象 (抽“像”)
  • 三大特性:
    • 封装
    • 继承
    • 多态
  • 从认识论的角度考虑是先有对象,后又类。对象,是具体的事物。类,是抽象的,是对 对象的抽象
  • 从代码运行角度考虑先有类后又对象。 类是对象的模板。

2 回顾方法的定义

​ 去看方法的定义,这里就不写了。

​ 为什么需要public static void main(String[] args)这个方法?

答:在未分类中详细说了。去看看。

3 回顾方法的调用

​ 去看方法的调用,主义静态方法,非静态方法,调用的异同。

什么是类的实例化?

类是指:描述一种事物的定义,是个抽象的概念
实例指:该种事物的一个具体的个体,是具体的东西

打个比方:
“人”是一个类。“张三”是人类的一个具体例子

在编程时也是同样的道理,你先自己定义一个“类”,当你需要用时,用“类”的定义来创造一个具体的例子。

用类的定义来创建一个实例,就叫做类的实例化。
    
    
     // 对象类型  对象名 = 对象值
        Student student = new Student();

匿名对象来调用:  new Student().say()

匿名对象

匿名:简单的说就是没有名字的对象

匿名优点:节省为 ‘ 对象地址 ’ 开辟的空间

 正常写法: 
 			Student  stu = new Student();
 			String name = stu.getName ;
 			new Student() 对象的名字为stu;
 			
>   匿名写法:
>         1.  Student[] stu = new Student[100];
>             stu[0] = new Student();
           表示的是stu数组的第一个元素为一个Student的对象,并且 new Student() 是没有名字的。
           2 直接用对象调用方法
             new studnet().getName;
>         

铺垫:

package pers.kang.demo01;


public class E {
    public static void main(String[] args) {

        Person per = new Person();
        System.out.println(per.name); // null

        change(per);   // 给方法传入参数
        System.out.println(per.name);  // 小明
    }


    public static void change(Person person) {   // 把 per 堆空间使用权,交给person,所以person可以调用属性

        // person 是一个对象:指向的是--->   Person person = new Person();  是一个具体的人
        person.name = "小明";
    }

}


class Person {
    String name;  // null
}




4 类与对象的创建

4.1 类 和 对象是什么?

  • 类是一种抽象的数据类型,它是对一类事务整体描述/定义,但是并不能代表某一个具体的事物
    • 动物,植物,手机,电脑
    • Person类、Pet类 、Car类 等,这些类都是用来描述/定义某一类具体的事物应该具备的特点和行为
  • 对象是抽象的概念的具体实例
    • 张三 就是人的具体实例,张三 的 旺旺 就是狗的具体实例。
    • 能够体现出特点,展现出功能的是具体实例,而不是一个抽象的概念。

4.2 创建和初始化对象

  • 使用 new 关键字创建对象

  • 使用 new 关键字创建的时候,除了分配内存空间之外,还会给创建好的对象 进行默认的初始化,以及对类中构造器的调用

// 一个项目应该只存在一个 main 方法
public class Application {

    public static void main(String[] args) {

        // 类:抽象的,实例化
        // 类实例化后会返回一个自己的对象!    Student xiaoming = new Student();
         // student对象就是一个Student 类具体的实例! 比如上面这个,嘿嘿!
        Student student = new Student();
        student.name = "小明明";
        student.age = 3;
        System.out.println(student);
        student.study();

    }


    
    
// 学生类
public class Student {

    // 属性: 字段
    String name;  // 我们没有赋值的时候,就是null
    int age;    // 默认: 0

    public void study(){
        System.out.println(this.name+",学习ing");
    }

5 构造器详解

类中的构造器也称为构造方法,是在进行创建对象名的时候必须调用的。并且构造器有一下两个特点:

    1. 必须和类的名字相同(如果一个源文件中有多个类,那么构造器必须与公共类同名)
    2. 必须没有返回类型,也不能写 void
    3. 每个类可以有一个以上的构造器 (我们查看了反编译后的字节码文件,可以看到,一个类即使什么都不写,它也会存在一个方法,就是构造方法)
    4. 构造器可以有0个、1个或1个以上的参数
    5. 构造器总是伴随着new操作一起调用
  • 很重要!!!

作用:

  1. 使用 new 关键字,本质是在调用构造器 (可以这样理解,通过new关键字去调用构造方法)
  2. 初始化对象的值

注意点:

  • 一旦定义了有参构造,想使用无参,无参就必须显示构造

  • 注意:不管有没有用,把无参构造带上,肯定不会报错(规范)

可以同时有无参构造和有参构造吗?

​ 可以的,都是在构造的时候被调用。
​ 如果在创建对象时不写参数,调用的就是无参的构造方法。可是如果你写的有有参的构造方法,而没有无参的构造方法,那么再“创建对象时不写参数”就会报错,程序会认为你知道该怎么做。
​ 如果构造方法有参数,在创建对象时传入了参数,那么就会调用此方法,这一点和重载类似。

6 创建对象内存分析

(和类一起加载)

  • 类和方法的定义:储存在堆区的方法区

  • 定义的静态方法区会储存 static 性质的方法 和数据类型

  • 定义对象名,储存在栈区。

  • new 会在堆区开辟一个专属的空间,此时会给属性赋值默认值(这里看看 java 中 8 个基本数据类型的默认值),并储存到堆区。

7 简单小结类与对象

1、类与对象

​ 类是一个模板: 抽象 ; 对象是一个具体的实例

2、方法

​ 定义、调用

3、 对应的引用

​ 引用类型:基本类型(8)

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

4、 属性,字段 Field 成员变量

​ 默认初始化:

​ 数字: 0, 0.0

​ char: u0000

​ boolean:false

​ 引用:null

修饰符 属性类型 属性名 = 属性值

5、 对象的创建和使用

  • 必须使用 new 创建对象,构造器 Person xiaoming = new Person();
  • 对象的属性, xiaoming.name;
    • 对象的方法:person.shout();

6、类:

静态的属性 属性

动态的行为 方法

类 = 属性 + 方法

8 封装

  • 该露的露,该藏的藏
    • 我们程序设计的要追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成;低耦合:仅暴露少量的方法给外部使用。
  • 封装(数据的隐藏)
    • 通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。
  • 记住这句话就够了:属性私有,get / set,设置 set 成员变量存取限制
package pers.kang.demo04;

// private:私有
/*
 1、提高程序的安全性,保护数据
 2、隐藏代码的实现细节
 3、统一接口
 4、系统可维护增加了


 一般情况是不会对 getter / setter 方法重载的
 大部分对构造器进行重载
 */
public class Student {

    // 属性私有
    private String name;  // 名字

    private int id;   // 学号

    private char sex;  // 性别

    private int age;  // 年龄

    // 提供一些可以操作这些属性的方法
    // 提供一些 public 的 get 和 set 方法



    // get: 获取这个数据 ;
    public String getName(){
        return this.name;
    }
    // set: 给这个数据设置值
    public void setName(String name){
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

/*
    大多数情况我们只对属性封装,方法用的比较少
     */

    // 学习()
    // 睡觉()
}


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



        s1.setName("小明");
        System.out.println(s1.getName());

        s1.setAge(-1);  // 不合法的
        System.out.println(s1.getAge());
    }
}

9 继承

  • 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
  • extends 的意思是 “扩展”。 子类是父类的扩展。
  • Java 中类只有单继承,没有多继承! (一个类可以被多个类继承,但是不能继承多个类)
  • 继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖,组合,聚合等。
  • 继承关系的两个类,一个为子类(派生类),一个为父类。子类继承父类,使用关键字extends来表示。
  • 子类和父类之间,从意义上讲,应该具有 “is a ” 的关系。

public protected default private

继承是一个宏观的把握,封装实现细节,多态也和继承有关系。所以很重要

子类继承父类就会继承父类的全部方法;

子类不能继承父类私有的东西,父类私有的东西,子类无法继承。 但是可以提供public 的 getter/setter 方法,子类就可以继承并且使用了。


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

Ctrl + H :打开”继承树“

// 父类
public class Person {

     public int money = 100_0000_000;

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

}
//  子类      学生  is  人
public class Student extends Person {

}

// 测试类
public class Application {

    public static void main(String[] args) {
        Student student = new Student();
        student.say();
        System.out.println(student.money);
    }
}


10 this 和 Super 详解

this 关键字

​ 1、指代当前对象 (常用于对象的比较操作,就是比较对象是否一样)

​ 2、指代当前类

​ 3、 指代本类构造方法 this(): 表示当前类的构造方法,只能放在首行

super 关键字

  1. 只能指代父类对象
  2. 指代父类的构造方法,只能放在首行

注意

  1. 子类必须通过 super 关键字调用父类有参数的构造函数

  2. 使用 super 调用父类构造器的语句必须是子类构造器的第一条语句

  3. super 必须只能出现在子类方法或者构造方法中

super 和 this 不能同时调用构造方法,因为他俩都要放在首行,会冲突,总会有一个报错

​ 如果子类构造器没有显式地调用父类的构造器,则将自动调用父类的默认(没有参数)的构造器(在子类构造中隐藏了 super())。

​ 如果父类没有不带参数的构造器,并且在子类的构造器中又没有显式地调用父类的构造器,则java编译器将报告错误

Ctrl + F 在类中搜索

// 父类
public class Person {
    protected String name = "小明明";

    // 私有的东西无法被继承

    public void print() {
        System.out.println("Person");
    }
}
//子类
public class Student extends Person {
    private String name = "小明";

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

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

    public void test1() {
        print();  // Student
        this.print();  // Student
        super.print();   // Person
    }
}
// 测试类
public class Application {

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


        student.test("小哈");
        student.test1();

    }
}

11 方法重写

重点---->> 多态

// 重写都是方法的重写,和属性无关,且针对的是非静态方法,和静态无关

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

  1. 方法名必须相同
  2. 参数列表必须相同
  3. 修饰符:范围可以扩大,但不能缩小: public > protected > default > private
  4. 重写可能会抛出异常,范围,可以被缩小,但不能扩大:ClassNotFoundException---> Exception (小)

子类继承父类后,重写父类的方法,子类的方法和父类必须一致,方法体不同!

那 为什么要重写?

  1. 父类的功能,子类不一定需要,或者不一定满足
  2. Alt+insert; override;

方法重载和重写是不同的概念,主要有以下区别:

1、首先是含义不同

1)方法重载是在同一个类中,声明多个同名方法,通过参数列表来区分不同的方法,与参数列表的数量、类型和顺序有关,与修饰符和返回值类型以及抛出异常类型无关

2)方法重写的前提是发生在具有继承关系的两个类之间,方法重写有以下规则:

a.参数列表必须保持一致

b.返回值类型必须保持一致

c.方法名必须保持一致

d.重写方法的访问权限范围必须大于等于父类方法

e.重写方法的抛出异常类型范围不能大于父类方法

2、方法的重载和重写的作用不同

重载:在一个类中为一种行为提供多种实现方式并提高可读性

重写:父类方法无法满足子类的要求,子类通过方法重写满足需求

实例:

重载:构造方法的重载、println() 方法重载

重写:Object 类的 toString()、equals()、hashCode() 等都可以被子类重写

我们用图来看一下:

12 多态

12.1 什么是多态?

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

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

  • 动态编译:类型 可扩展性

12.2 多态存在的条件

  • 有继承关系

  • 子类重写父类方法

  • 父类引用指向子类对象

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

*类型转换异常:ClassCastException 看到这个我们就知道,子父类出现了问题

public class Application { 

    public static void main(String[] args) {

        // 一个对象的实际类型是确定的
        // new Student();
        // new Person();

        // 可以指向的引用类型就不确定了,父类的引用指向子类

        Student s1 = new Student();  // Student 能调用的调方法都是自己的或者继承父类的
       
        //父类的引用指向子类对象
        Person s2 = new Student();   // Person 父类型,可以指向子类,但是不能调用子类独有的方法,如果子类没有重写,调用父类的方法,因为子类继
                                        //承了父类全部的方法, 子类重写了父类的方法,则调用子类重写的方法。
        Object s3 = new Student();
       
       // 对象能执行那些方法名主要看对象左边的类型,和右边关系不大
        s2.run();
        s1.eat();
        ((Student)s2).eat();    
    }
}

13 instanceof 和 类型转换

作用:用来测试一个对象是否为一个类的实例

boolean result = obj  instanceof Class

​ 其中 obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或间接子类,或者是其接口的实现类,结果result 都返回 true,否则返回false。

  注意:编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,具体看运行时定。

 我们新建一个父类 Person.class,然后在创建它的一个子类 Man.class

public class Person {}

  Man.class

public class Man extends Person{  }

  测试:

Person p1 = new Person(); 
Person p2 = new Man();
Man m1 = new Man();
System.out.println(p1 instanceof  Man); //false
System.out.println(p2 instanceof Man); //true
System.out.println(m1 instanceof Man);  //true

  注意第一种情况, p1 instanceof Man ,Man 是 Person 的子类,Person 不是 Man 的子类,所以返回结果为 false。

类型转换:

//
Student studnet = new Studnet;

高转低
Person per = student;    // 父类引用指向子类对象

1、父类引用只想子类对象
    2、把子类转换为父类,向上转型
    3、把父类转换为子类,向下转型;  强制转换
    4、方便方法的调用,减少重复的代码。

14 static 关键字

在同一个类中:

- 对于静态变量,静态和非静态方法都可以直接调用。

-  对于非静态变量,非静态可以直接调用,静态只能通过对象来调用它。

在不同类中:无论调用时非静态还是静态,如果被调用的变量是:

- 静态变量:类名.属性名调用

- 非静态变量:只能通过对象才可以调用它。

还有静态方法,非静态方法的调用,去方法.md去看

package pers.kang.demo05;


import com.sun.media.sound.SoftTuning;

public class Application {
    //2、
    {
        System.out.println("匿名代码块");
    }
   //1、  只执行一次,且最先执行,赋初值
    static {
        System.out.println("静态代码块");
    }
    //3、
    public Application() {
        System.out.println("构造方法");
    }

    public static void main(String[] args) {
        Application a = new Application();
        System.out.println("===========================");
        Application a1 = new Application();
    }


}

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

Process finished with exit code 0

静态导入包

package pers.kang.demo05;

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

15 抽象类

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

  • 抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类。

  • 抽象类,不能使用 new 关键字来创建对象,它是用来让子类继承的。

  • 抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的。

    • 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。
    //约束  有人帮我们实现~
    // abstract ,抽象方法,只有方法名字,没有方法的实现

    public abstract void doSomething();

    //1、它的特点,其实它没有什么特点,因为它太抽象了
    //   不能 new 这个抽象类,只能靠子类去实现它:约束!
    //2、抽象类可以写普通方法
    //3、 抽象方法必须写在抽象类中,抽象的抽象,约束

    // 为什么要用抽象类呢?  因为它可以提高开发的效率,节省代码的书写。
}


// 抽象类的所有方法,继承了它的子类,都必须要实现它的方法  除非它的子类也是抽象类,那就要它的子子类去实现了
public class A extends Action {
    @Override
    public void doSomething() {

    }
}

16 接口的定义 与 实现

类很抽象,抽象类更加抽象,接口比抽象类还抽象!

它没有构造方法,不能 new,也就是不能实例化

  • 普通类:只有具体实现

  • 抽象类: 具体实现和规范(抽象方法)都有!

  • 接口:只有规范!自己无法写方法, 专业的约束! 约束和实现分离:面向接口编程

  • 接口就是规范,定义的是一组规则,体现了现实世界中“ 如果你是.....则你必须能.....” 的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。如果你是好人,则必须干掉坏人;如果你是坏人,则必须不干好事。

  • 接口的本质是契约,就像我们人间的法律一样。制定好,大家都要遵守。

  • OO(面向对象) 的精髓,是对 对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备抽象能力的语言(比如C++ , java, c#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。


我的解释:

​ 接口可以理解为一种特殊的类,里面全部是由全局常量公共的抽象方法所组成。接口是解决Java无法使用多继承的一种手段,但是接口在实际中更多的作用是制定标准的。或者我们可以直接把接口理解为100%的抽象类,既接口中的方法必须全部是抽象方法。(JDK1.8之前可以这样理解)


接口的特点:

​ 就像一个类一样,一个接口也能够拥有方法和属性,但是在接口中声明的方法默认是抽象的。(即只有方法标识符,而没有方法体)。

  • 接口指明了一个类必须要做什么和不能做什么,相当于类的蓝图。
  • 一个接口就是描述一种能力,比如“运动员”也可以作为一个接口,并且任何实现“运动员”接口的类都必须有能力实现奔跑这个动作(或者implement move()方法),所以接口的作用就是告诉类,你要实现我这种接口代表的功能,你就必须实现某些方法,我才能承认你确实拥有该接口代表的某种能力。
  • 如果一个类实现了一个接口中要求的所有的方法,然而没有提供方法体而仅仅只有方法标识,那么这个类一定是一个抽象类。(必须记住:抽象方法只能存在于抽象类或者接口中,但抽象类中却能存在非抽象方法,即有方法体的方法。接口是百分之百的抽象类)

为什么要用接口:

  1. 接口被用来描述一种抽象。

  2. 因为Java不像C++一样支持多继承,所以Java可以通过实现接口来弥补这个局限。

  3. 接口也被用来实现解耦。

  4. 接口被用来实现抽象,而抽象类也被用来实现抽象,为什么一定要用接口呢?接口和抽象类之间又有什么区别呢?

    答:原因是抽象类内部可能包含非final的变量,但是在接口中存在的变量一定是final,public,static的。


关于接口的几个重点:

  1. 我们不能直接去实例化一个接口,因为接口中的方法都是抽象的,是没有方法体的,这样怎么可能产生具体的实例呢?

    答:我们可以使用接口类型的引用指向一个实现了该接口的对象,并且可以调用这个接口中的方法。(实际上就是使用了Java中多态的特性)

声明类的关键字是 class, 声明接口的关键字是 interface

// 抽象的思维~  JAVA  架构师

// 定义的关键字是:interface   接口都需要有实现类
public interface UserService {
    //接口中的所有定义方法其实都是抽象的  public abstract 隐藏了,没有写

   // 属性默认的也是一个常量,
    public static final int age = 99;


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

}
public interface TimeService {
    void timer();
}


// 抽象类:  extend  单继承  就有局限性了
//  为啥会爆红呀? 还没有实现接口中的方法    因为实现接口要实现里面的所有规范
// 实现了接口的类,就要重写接口的中的方法,少一个都不行
// 接口可以实现多继承,
public class UserServiceImpl 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() {

    }
}

17 N 种内部类

17.1 什么是内部类?

定义: 将一个类定义在一个类或者一个方法里面,这样的类称着内部类

  • 内部类就是在一个类的内部再定义一个类,比如,A类中定义一个B类,那么B类相对于A类来说就称为内部类,而A类相对于B类来说就是外部类了。

17.2 内部类的种类

  1. 成员内部类
  2. 静态内部类
  3. 局部内部类
  4. 匿名内部类
posted @   走马!  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示