java学习day07

类和对象

什么是面向对象

面向过程(线性思维)

步骤清晰简单,第一步做什么,第二步做什么

面向对象

物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考,最后才对某个分类下的细节进行面向过程的思索

对于描述复杂的事物,为了从宏观上把握,从整体上合理分析,我们需要使用面向对象的思路类分析整个系统,但是,具体到微观操作,仍然需要面向过程的思路去处理

面向对象编程(Object-Oriented Programming,OOP)

采用面向对象的方式贯穿整个系统的话,涉及三个术语:

  OOA:面向对象分析

  OOD:面向对象设计

  OOP现象对象编程

实现一个软件的过程:

  分析(A)-->设计(D)-->编程(P)

面向对象编程的本质就是:以类的方式组织代码,以对象的方式组织(封装)数据

面向对象的三大特性

  封装

  继承

  多态

类和对象的关系

实际上在现实世界中是不存在的,是一个抽象概念,是一个模板,是人类大脑进行思考、总结、

抽象的一个结果,类本质上是现实世界中某些事物具有共同特征,将这些共同特征提取出来形成的概念就是类

类就是一个模板

对象是实际存在的个体,在java语言中要想得到对象,必须先定义类,对象是通过类这个模板创造出来的个体

类:不存在,人类大脑思考总结的一个模板(这个模板描述了共同特征)

对象:实际存在的个体

实例:对象的另一个名称

实例化:通过类这个模板创建对象的过程,叫做实例化

抽象:多个对象具有共同特征,进行思考总结抽取共同特征的过程

类--【实例化】-->对象(实例)

对象--【抽象】-->类

类=属性+方法

属性:状态(属性在代码上以变量的形式存在)

方法:动作/行为

类的定义

语法:

[修饰符列表] class 类名{}

public class Demo2 {

}

创建与初始化对象(构造器)

使用new关键字创建对象

public class Demo2 {
    public static void main(String[] args){
       B b = new B();
    }
}
class B{
    
}

使用new关键字,除了分配内存空间之外,还会给调用构造器

b叫做引用,保存对象的内存地址的变量

构造器

类中的构造器也称为构造方法,使用new关键字创建对象时会调用构造器,构造器必须满足两个特点

1、必须和类的名字相同

2、必须没有返回值类型,也不能写void

注意点:

没有定义任何构造方法,系统会提供一个无参构造器(缺省构造器),定义有参构造之后,就必须定义出无参构造,否则无法使用无参构造创建对象

封装

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

高内聚:就是类的内部数据操作细节自己完成,

低耦合:仅暴露少量方法给外部使用

封装:通常应禁止直接访问一个对象中的数据的实际表示,而应通过操作接口来访问,成为信息的隐藏

属性私有,getter/setter方法

 get(读)方法要求:
        public 返回值类型 get+属性名首字母大写(无参){
          return xxx;
        }

   set(改)方法要求:
         public void set + 属性名首字母大写(有参){
         //可以设置关卡如使用条件语句
         xxx = 参数;
         }

封装属性:

第一步:属性私有化

private int i;

第二步:添加set和get方法

public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }

封装有什么用?

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

继承

extends的意思是扩展,子类是父类的扩展

java中所有类都默认直接或间接继承Object类

继承的作用:

  基本作用:代码复用

  重要作用:方法重载和多态

public class Test{

    public static void main(String[] args) {
        B b = new B();
        System.out.println(b.getI());
    }


}
class A{
    private int i;
    int n;

    public A() {
        i = 10;
    }

    public A(int i, int n) {
        this.i = i;
        this.n = n;
    }

    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }
}
class B extends A{

}

注意:

  子类会继承父类的一切东西,除了构造方法之外,私有的也可以继承,只不过私有的无法直接访问

继承的相关特性

  1、B类继承A类,则称A类为超类、父类、基类,B类则称为子类、派生类、扩展类

  2、java中只支持单继承,不支持多继承

  3、虽然java不支持多继承,但有的时候会产生间接继承的效果,例如:B类继承A类,C类继承B类,间接C类也继承了A类

  4、java中规定子类继承父类,除构造方法不能继承外,其他都可以继承,但是私有的属性无法在子类中直接访问(要使用set和get方法访问)

  5、java中的类没有显示继承任何类,则默认继承Object类,一个对象与生俱来就有Object类中所有的特征

  6、继承会导致类直接的耦合度变高

子类继承父类之后,能通过子类调用父类的方法,本质上,子类继承父类之后,是将父类继承过来的方法归自己所有,

实际上调用的是子类自己的方法(因为已经继承过来了,是属于自己的)

什么时候去继承?

  从语言描述来说:凡是采用“is a”能描述的,都可以继承

  从代码上来说:不同类中有过多的相同的代码,可以使用继承,如果两个类之间有公共代码,但是不能使用is a的方式去描述,不建议使用继承

this和super

this

this是一个关键字,代表当前对象,this只能用在实例方法和构造器中,this.大部分情况下可以省略,省略后还是默认访问当前对象的实例变量,

this()只能出现在构造器的第一行,用来调用另一个构造器,this有时候不能省略

public class Test{

    public static void main(String[] args) {
        A a = new A();
        System.out.println(a.i);//10
    }
}
class A{
    int i;

    public A(int i) {
        this.i = i;
    }

    public A() {
        this(10);
    }
}

为了区分局部变量和实例变量,此时this不能省略

super

super是一个关键字代表当前对象的父类,super只能出现在实例方法和构造器中,super大部分情况下可以省略

但是在区分子类和父类同名属性时,super不能省略,super()只能出现在构造器的第一行,当有继承关系时,系统会在

构造器的第一行写上super() 

public class Test{

    public static void main(String[] args) {
        A a = new A();

    }
}
class A extends B{
    int i;

    public A(int i) {

    }

    public A() {
        super();
        System.out.println("子类构造方法");
    }
}
class B{
    public B() {
        System.out.println("父类的构造方法");
    }
}

即使不写super()系统也会默认添加

注意:this()和super()不能同时存在,如果已经存在了this()那么系统就不会添加super()

方法重写(方法覆盖、Override)

什么是方法重写

  当子类中出现和父类方法头一样但是方法体不一样的方法就是方法重写

什么时候用到方法重写

  子类继承父类,当继承过来的方法无法满足子类业务需求时,子类就有必要对这个方法进行重写

注意:当子类进行方法重写后,子类调用该方法时,一定是调用覆盖之后的方法

如何进行方法重写

  1、两个类直接必须有继承关系

  2、重写之后的方法和之前的方法相比必须满足一下条件

    相同的返回值类型(对于基本数据类型必须一致,对于引用数据类型可以是原数据类型的子类)

    相同的方法名

    相同的形参

  3、访问权限不能更低,可以更高

  4、重写后的方法不能比之前的方法抛出更多的异常,可以更小

注意事项:

  1、方法覆盖知识针对方法和属性无关

  2、私有方法不能覆盖

  3、构造方法不能被继承,所有构造方法不能被覆盖

  4、方法覆盖只是针对实例方法,静态方法覆盖没有意义

被static、final、private修饰的方法不能覆盖

多态

向上转型:父类型引用指向子类型对象

public class Test{

    public static void main(String[] args) {
        Animal a1 = new Cat();
        a1.eat();
    }
}
class Animal{
    public void eat(){
        System.out.println("动物吃东西");
    }
}
class Cat extends Animal{
    public void eat(){
        System.out.println("猫吃老鼠");
    }
}

对a1.eat()代码解析

  编译阶段:

    对于编译器来说,编译器只知道a1类型是Animal,所有编译器在检查时会去找Animal.class

    字节码文件(编译阶段不创建对象,编译器只知道a1是Animal类型)中找eat方法,找到了绑定

    上eat()方法,编译通过,静态绑定成功(编译阶段属于静态绑定)

  运行阶段:

    运行阶段的时候,实际上会在堆内存中创建的ava对象Cat对象,eat方法是Cat的方

    法,所以运行阶段会动态执行Cat对象的eat()方法,这个过程属于运行阶段绑定(运行

向下转型:子类型对象指向父类型引用(存在风险)

A b = new B();//向上转型
A a1 = new A();
B a = (B) a1;//向下转型

无论是向上转型还是向下转型两者之间都必须有继承关系

使用向下转型时要和instancOf一起使用,否则会出错

instanceOf:二元操作符,可以再运行阶段动态判断引用指向对象的类型

  语法:引用 instanceOf 类型

if (a2 instanceof Cat){//为什么要这么写?
    Cat c = (Cat)a2;
    c.eat();
}

判断左边引用是否为右边的实例

多态

什么是多态?

  多态指的是多形态,多状态,包括编译阶段和运行阶段

编译阶段:绑定父类方法

运行阶段:动态绑定子类的方法

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

  一个对象的实际类型是确定的,但可以执行对象的引用的类型很多

  父类引用可以执行对象,但是无法调用子类特有的方法

  如果想要使父类的引用可以调用子类特有的方法需要进行向下转型

多态存在的条件:

  有继承关系

  子类重写父类方法

  父类引用指向子类对象

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

多态表示多种形态:编译时一种形态,运行时另一种形态

多态在开发中的作用

  降低程序耦合度,提高程序扩展力

在软件扩展中,修改越少越好,软件开发原则有七大原则,其中一条最基本的原则:OCP(开闭原则)

什么是开闭原则?

  对扩展开放,对修改关闭

final

final是java语言的关键字,表示最终的,不可变的,可以修饰变量,方法,类等

final修饰类

final修饰的类无法被继承

final class A{
    
}

final修饰方法

final修饰的方法无法被覆盖

class C{
    //不希望别人覆盖方法可以添加final修饰方法
    public final void doSome(){
        System.out.println("C,doaome");
    }    
}

final修饰变量

final修饰的变量只能赋一次值

final修饰局部变量

final修饰的局部变量,一旦被赋值,就不能重新赋值

final修饰成员变量

final修饰的成员变量系统不会赋默认值

final static int a = 1;

final修饰引用

引用也是一个变量

final修饰的引用,只能指向一个对象,并且只能永远指向该对象,无法再指向其他对象,该对象不会被垃圾回收器自动回收(没有任何引用指向的对象会被回收)

final Person p = new Person(30);

常量

常量的定义

  final 数据类型 变量名 = 值;

final int i = 10;

抽象类

什么是抽象类?

  类与类之间有共同特征,将这些共同特征提取出来,形成的就是抽象类,类本身

  不存在,所以抽象类无法实例化,抽象类也属于基本引用数据类型,抽象类是用

  来被子类继承的

定义抽象类

  权限修饰符 abstract class 类名{}

public abstract class Test{
}

抽象类的子类可以是抽象类也可以是非抽象类

final和abstract不能同时出现,因为抽象类注定是要被继承的,而final修饰的类是不可以被继承的

抽象类虽然无法实例化,但是有构造方法,这个构造方法是供子类使用的,抽象类中有抽象方法

什么是抽象方法?

抽象方法表示没有实现的方法,没有方法体的方法

public abstract void doSome();

抽象方法的特点

  1、没有方法体,以分号结尾

  2、用abstract关键字修饰

抽象方法被子类继承后需要将抽象方法进行重写或者也可以叫做实现

注意:一个非抽象的类继承一个抽象类,必须将抽象类中的抽象方法实现了,这是java语法上

   强行规定的,必须的,不然编译器会报错,如果是抽象类继承另一个抽象类,则不用

   重写抽象方法

没有方法体的方法不一定是抽象方法,Object类中就有没有方法体的方法,但它们不属于抽象

方法,而是c++的动态链接库

抽象类也属于引用数据类型

接口

什么是接口?

  接口是完全抽象的,抽象类是半抽象的,或者是接口是特殊的抽象类

定义接口

修饰符列表 interface 接口名{}

public interface A{
}

接口的特点

  接口支持多继承,一个接口可以继承多个接口

interface C extends A,B{
}

接口只含有常量和抽象方法,接口中的所有元素默认是public修饰的,接口定义抽象方法时

public abstract可以省略,因为这是默认的,定义常量时public static final可以省略,这也是默认的

一个非抽象类继承接口时,必须将接口的所有方法实现

接口和接口之间可以多继承,一个类和接口之间也支持多继承,类继承接口叫做实现,一个类可以

同时实现(implements)多个接口

interface AB{
    void ab();
}
interface CD{
    void cd();
}
interface EF{
    void ef();
}
class V implements AB,CD,EF{
    public void ab() {}
    public void cd() {}
    public void ef() {}
}

这种机制弥补了java中单继承带来的缺陷

当继承和实现同时存在,代码怎么写?

  extends关键字在前,implements关键字在后

接口和抽象类的区别

                抽象类      接口   

定义的关键字          abstract       interface

子类继承或实现关键字      extends       implements

方法实现            可以有      不能有,但在jdk8之后,允许有default实现

方法访问控制符         无限制      有限制,默认是public abstract类型

属性访问控制符         无限制      有限制,默认是public static final类型

静态方法            可以有      不能有,但在jdk8及之后,允许有

static{}静态代码块        可以有      不能有

本类型之间扩展         单继承      多继承

本类型之间扩展关键字      extends       extends

interface B{
    //default方法
    default void i(){
        System.out.println("hello");
    }
    //静态方法
    static void a(){
        System.out.println("hello");
    }
}

Object类

toString()方法:输出引用时会默认调用该引用的toString方法,建议所有子类重写此方法

equals()方法:判断两个基本数据类型是否相等直接使用==就行,判断两个java对象是否

      相等要使用equals方法,==判断的是内存地址,而equals判断的是内容,

      建议所有子类重写equals()方法

finalize()方法:这个方法是protected修饰的,这个方法不需要程序员手动调用,JVM的垃圾

       回收器负责调用,finalize()方法只需要重写,不需要调用,这是一个时机,垃圾

       销毁时机,自从jdk9之后这个方法就过时了,System.gc()建议启动垃圾回收器

hashCode()方法:该方法返回的是哈希码,实际上就是一个java对象内存地址,经过哈希算法得出的一个值

        所有hashCode()方法的执行结果可以等同看做一个java对象的内存地址

clone()方法:有深克隆和浅克隆

getClass()方法:返回对象的完整类名(包括完整类名),返回一个Class对象

posted @ 2021-09-25 20:13  hello小番茄  阅读(45)  评论(0)    收藏  举报