Java-面向对象


1、面向对象 & 面向过程

  • 面向过程

步骤清晰简单,第一步做什么,第二步做什么… 就像是你今天中午要炒菜,炒一个鸡蛋西红柿,第一步,洗西红柿,切西红柿,第二步打鸡蛋,第三步放点盐,第四步,开火,放油… 一步一步来。

面向过程去处理这种一系列较为简单的问题。

  • 面向对象
  1. 物以类聚,分类的思维模式,思考问题首先回解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。比如你炒菜需要分类:素菜和荤菜,把类实例化一个对象.素菜今天的实例对象是鸡蛋西红柿,麻辣豆腐。然后才对具体对象 菜的做饭进行面向过程的探索
  2. 面向对象适合处理复杂的问题,适合处理需要多人协作的问题!
  3. 对于复杂的事物,我们需要用面向对象的思路在宏观上分析整个系统。 对于细微之处,仍然需要面向过程的思路去处理。

那么什么是面向对象?

  • 面向对象编程(Object-Oriented Programming.OOP)
  • 面向对象编程的本质就是:以类的方式组织代码,以对象的形式组织(封装)数据

1.2、类和对象的关系

类是一种抽象的数据类型,它是对某一类事物整体的定义, 但是不能代表某一个具体的事物。比如素菜、荤菜、川菜、湘菜…

对象是 抽象的类这个概念 的 一个具体实例。比如:鸡蛋西红柿就是 素菜的一个具体实例; 剁椒鱼头就是湘菜的一个具体实例。

Java 语言是面向对象的:Java 语言提供类、接口和继承等面向对象的特性,为了简单起见,只支持类之间的单继承(extends),但支持接口之间的多继承,并支持类与接口之间的实现机制(关键字为 implements)

对象是根据类创建的。在Java中,使用关键字 new 来创建一个新的对象。创建对象需要以下三步:

  1. 声明:声明一个对象,包括对象名称和对象类型。
  2. 实例化:使用关键字 new 来创建一个对象。
  3. 初始化:使用 new 创建对象时,会调用构造方法初始化对象。

下面是一个创建对象的例子:

public class Puppy{  
    public Puppy(String name){   
        //这个构造器仅有一个参数:name   
        System.out.println("小狗的名字是 : " + name );  
    }  
    public static void main(String[] args){   
        // 下面的语句将创建一个Puppy对象   
        Puppy myPuppy = new Puppy( "tommy" );  
    }
}

1.3、创建和初始化对象

  • 使用new关键字创建对象。 前面的创建一个数组也是 new 新建一个。
  • 使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用
  • 类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。并且构造器有以下两个特点:
  1. 必须和类的名字相同
  2. 必须没有返回类型,也不能写void

关于构造器,即构造方法的解释, java默认创建的构造方法,我在前面有解释。

构造器详解

  1. 使用new 关键字,本质在调用构造方法
  2. 用来初始化对象的值

注意点:

  1. 定义有参构造之后,如果想使用无参构造,要显示定义一个无参的构造。

快捷键 alt+Insert 生成 构造器

1.3.1、抽象的类 实例化一个 对象

例子:定义一个学生类, 这个 class Student 的属性有name, age。 他是抽象的, 就好比 人 是一个抽象的 class。它不是一个具体的对象。

public class Student {
    //定义属性
    String name;
    int age;
    // study() 方法
    //this.属性   表示当前的属性
    public void study(){
        System.out.println(this.name+"学习快乐!");
    }
}

student 类实例化, 生成一个具体的对象,比如鑫仔 就是一个具体存在的 class Student。 鑫仔就是一个具体的人, 人是抽象的存在。 将 class Student 实例化, 创建具体的对象,如鑫仔,

//一个项目应该只有一个main 方法
public class Application {
    public static void main(String[] args) {
        //类: 抽象的
        //将类实例化后  就会返回一个当前的 自己的对象
        //student对象就是  类 Student实例化后一个具体的实例!
        Student student = new Student();
        Student xin = new Student(); //类Student,实例化一个具体的对象 xin
        xin.name = "鑫仔";
        xin.age = 18;
        System.out.println(xin.name);
        System.out.println(student.name);
        System.out.println(xin.age);
        System.out.println(student.age);
        xin.study();
    }
}

结果为:

鑫仔
null
18
0
鑫仔学习快乐!

上述的代码含义表示的就是:
以类的方式去组织代码,形成一个个类; 类中有不同的属性
然后以对象的形式去封装数据。 每个对象的属性有着具体值

1.3.2、构造器详解

每个类都有一个构造器,你不定义的时候,会有一个默认的构造方法。构造方法的修饰符和名字必须与类相同。

当你创建一个类,对类实例化一个 具体对象时, 即采用new关键字, 实际上你就在调用它的构造器了。这个构造器是用来初始化值的。

例子:

public class Person02 {
    //一个类即使什么都不写,它也会存在一个方法
    //显示的定义构造器
    String name;

    //实例化初值
    // 当使用new关键字时,本质就是在调用构造器
    public Person02(){  // 这个就是显示定义的构造器, 名字和修饰符必须要与类Person2一样
        this.name = "ALZN";
    }
    
    //有参构造,一旦定义了有参构造,无参就必须要显示定义
    public Person02(String name) {
        this.name = name;
    }
}
public class Application02 {
    public static void main(String[] args){
        //new 实例化一个对象。 就相当于调用了 类Person2 的构造器
        Person02 person02 = new Person02();

        System.out.println(person02.name); //结果为 ALZN
    }
}

我们可以发现,在Application02 中运行main方法时, 结果输出 ALZN, 但我们并没有赋值, 这是因为new 已经调用了构造器。

1.4、类与对象总结

  1. 类与对象
    类是一个模板:抽象的;对象是一个具体的实例
  2. 方法:定义、调用!
  3. 对应的引用
    引用型:基本类型(8种)
    对象是通过引用来操作的:栈---->堆
  4. 属性:字段Field成员变量
    默认初始化:数字: 0 0.0; char:u0000; boolean:false; 引用 null
  5. 对象的创建和使用:
  • 必须使用new 关键字创造对象,构造器Person person=new Person();
  • 对象的属性person.name
  • 对象的方法person.sleep();
  1. 类:
  • 静态的属性 属性
  • 动态的行为 方法

2、封装

  • 程序设计要追求“高内聚,低耦合”
  • 应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,称为信息隐藏。

记住这句重点:属性私有,get/set

封装一般是去针对 属性去做的。private/public 这两个修饰词来决定。

封装之后,为了获得属性,需要去采用get/set 这两种方法去定义一个公共的属性, 采用alt+insert 快捷键可以去定义get/set 的公共属性。

例子: 类中的属性私有 即封装, 则创建的具体对象 就不能获得,继承这些属性, 需要定义get/set 的公共属性

public class NewPerson1 {
    //属性私有
    private String name;
    private int age;
    
    //采用 ALT+INSERT 快捷键,来  get/set得到这些私有的属性
    // 创建一个公共属性
    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 class ApplicationNewPerson {

    public static void main(String[] args) {
        //new  实例化一个对象
        NewPerson1 newPerson = new NewPerson1();

        newPerson.setAge(18);
        newPerson.setName("ALZN");
        System.out.println(newPerson.getAge());
        System.out.println(newPerson.getName());
    }
}

结果:只有这样,才能继承 NewPerson1 的属性。

18
ALZN

3、继承

继承

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

父类扩展了一个子类, 子类 extends。 子类继承了父类的所有东西,比如方法, 属性

例子:父类:

public class Person1 {
    //人: 父类
    public int money= 10_0000_0000; //属性: money
    protected String name = "AL";

    //私有属性 age
    private int age = 40;
    
    public void say(){
        System.out.println("你好啊!");
    }

    //利用快捷键 ALT+ INSERT创建公共属性
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

子类:

//学生  是 人: 派生类,子类
// 采用  extends,表示父类的扩展 扩展为子类 student01
public class Student01 extends Person1{

    //子类继承了父类,虽然子类中没有定义,
    // 但会继承父类的全部  属性 和  方法
    private String name = "ZN";

    public void test(String name){
        System.out.println(name); //ALZN
        System.out.println(this.name); //ZN 本身调用者,当前对象的
        System.out.println(super.name);// AL. super,用于调用父类的
    }
}

测试:

public class Application01 {
    public static void main(String[] args) {
        // new  创建了一个新的子类 Student01, 子类变量名字为student01
        Student01 student01 = new Student01();

        System.out.println(student01.money); //继承了属性money
        student01.say();  //继承了方法 say().

        System.out.println(student01.getAge()); //继承公共属性

        student01.test("ALZN");
    }
}

测试的结果为:

1000000000
你好啊!
40
ALZN
ZN
AL

结果表明:

  • student01 是 对类Student01 实例化后的一个具体对象。
  • 子类Student01 会继承父类的属性和方法,
  • 但是父类的私有属性,必须要使用get/set 去建立公共的属性,子类才能继承
  • 需要注意的是 this 和 super。 this.name:本身调用者,当前对象的,这里是student01在test方法中测试时,在类Student01中调用,当前对象,即这段代码在Student01 中,它的name是ZN。super,用于调用父类的

super注意点:

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

this:代表的对象不同:

  • this:本身调用者这个对象
  • super:代表对 父类对象的引用

前提

  • this:没有继承也可以使用
  • super:只能在继承条件才可以使用

构造方法

  • this()本类的构造
  • super()父类的构造

4、方法重写

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

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

重写:子类的方法和父类必须要一致!方法体不同

为什么需要重写:父类的功能,子类不一定需要,或者不一定满足

快捷键:Alt+Insert: override

例子:关于方法重写:

public class TestOverride {
    public static void main(String args[]){
        Animal a = new Animal(); // Animal 对象
        Animal b = new Dog(); // Dog 对象

        a.move();// 执行 Animal 类的方法
        b.move();//执行 Dog 类的方法
    }
}
class Animal{
    public void move(){
        System.out.println("动物可以移动");
    }
}
class Dog extends Animal{
    public void move(){
        System.out.println("狗可以跑和走");
    }
}

结果为:

动物可以移动
狗可以跑和走

重写与重载之间的区别

区别点

重载方法

重写方法

参数列表

必须修改

一定不能修改

返回类型

可以修改

一定不能修改

异常

可以修改

可以减少或删除,一定不能抛出新的或者更广的异常

访问

可以修改

一定不能做更严格的限制(可以降低限制)

5、多态

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

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

多态存在的条件:

  1. 有继承关系
  2. 子类重写父类方法
  3. 父类引用指向子类对象

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

instanceof 引用类型类型转换。(下面会讲)

父类和子类,有联系,类型转换异常!ClassCastException!

不能重写方法:

1.static方法,属于类,不属于实例

2.final常量

3.private方法

5.1、instanceof和类型转换

instanceof(类型转换) 引用类型, 去判断一个对象是什么类型。

instanceof 严格来说是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例。

5.2、static关键字详解

有static时,直接在类下面定义的属性为静态属性;没有static就是非静态属性。

静态属性可以由类 class 也可以由方法直接去引用, 但是非静态属性只能由方法去引用。

例子:

//static
public class Student02 {
    private static  int age; //静态的变量    多线程
    private double score;
    
    public void run(){
    }
    
    public static void main(String[] args){
        Student02 s2 = new Student02();

        System.out.println(Student02.age);
        
        System.out.println(s2.age);
        System.out.println(s2.score);
    }
}

static方法也是类似

5.3、抽象类

  • abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法,name该方法就是抽象方法,如果修饰类,该类就是抽象类。
  • 抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类
  • 抽象类,不能使用new关键字来创建对象,它是用来让子类继承
  • 抽象方法,只有方法的声明,没有方法的实现,是用来让子类实现的
  • 子类继承抽象类,那么久必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。

5.4、接口

普通类:只有具体实现

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

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

接口就是规范,接口的本质是契约!!

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

作用

  1. 接口是一个约束
  2. 定义一些方法,让不同的人实现
  3. 方法只能创建抽象,创建 public sbstract
  4. 属性只能创建常量,常量创建 public static final
  5. 接口不能被实例化,接口中没有构造方法
  6. implements 可以实现多个接口
  7. 必须要重写接口中的方法

接口有多继承, 类只有单继承

Java 语言提供类、接口和继承等面向对象的特性,为了简单起见,只支持类之间的单继承,但支持接口之间的多继承,并支持类与接口之间的实现机制(关键字为 implements)。

单继承

Java 不支持多继承,只允许一个类直接继承另一个类,即子类只能有一个父类,extends 关键字后面只能有一个类名。例如,如下代码会导致编译错误:

class Student extends Person,Person1,Person2{…}
class Student extends Person,extends Person1,extends Person2{…}

尽管一个类只能有一个直接的父类,但是它可以有多个间接的父类。例如,Student 类继承 Person 类,Person 类继承 Person1 类,Person1 类继承 Person2 类,那么 Person1 和 Person2 类是 Student 类的间接父类。

多继承: 对于接口来讲,可以继承多个接口哦:

class Student implements Person,Person1,Person2{…}
class Student implements Person,extends Person1,extends Person2{…}

5.5、内部类

  1. 内部类
    内部类就是在一个类的内部再定义一个类,如,A类中定义B类,B类就是A类的内部类;反之,A类是B类的外部类。
  2. 成员内部类:在类的里面写一个类
  3. 静态内部类:在类的里面写一个stiatic修饰的类
  4. 局部内部类:在类的方法里面写一个类
  5. 匿名内部类