面向对象

一切事物都为对象
包括封装、继承、多态

类和对象

java通过类描述事物,类由属性、行为构成,类是一切具有相同属性和行为的统称

抽象是将所有的属性和行为提取出来的过程

对象是某一类事物的某个具体存在,通常也称为实例instance

事物的属性称为成员对象成员变量

事物的行为称为成员方法

成员变量在声明时可以直接赋值,声明后不能在类中赋值,所以继承后的类中不能给父类中的成员变量在类内赋值

创建对象

即类的实例化

类名 对象名 = new 类名();

创建对象:new+构造器(),如果没有定义显式的构造器,则系统默认提供一个空参构造器

匿名对象:new 类名().方法/属性,即不设置变量名

构造器

构造器可以用来初始化对象,即在实例化对象时,在括号内添加相应的参数

class 类名{
    权限 与类名相同的方法名(参数列表){
        语句;
    }
}

构造器可以有多个,即构造器支持重载,可以把构造器看作是返回值为void的方法

class Animal{
    String name;
    private int weight, height;
    public Animal(String name){
        this.name = name;
    }
    public Animal(){
        System.out.println("创建成功,没有提供构造器的参数");
    }
    public void  setName(String name) {
        this.name = name;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public void setHeight(int height) {
        this.height = height;
    }
}

构造一个Animal类

Animal dog = new Animal("狗");
//此时相当于执行的第四行,为name成员变量赋值的方法

Animal dog = new Animal();
//此时相当于执行的第七行,直接输出 创建成功,没有提供构造器的参数

使用对象

使用成员对象 类名.变量名

使用成员方法 类名.方法名();

成员变量:定义在类中 方法外,默认值为null

成员方法:去掉static修饰符

类需要存储在一个新建文件中,如果调用类,则再次新建一个类,类里边包含main进行调用

可以使用对象名.变量名直接对类内非私有变量直接赋值

#####创建类

package 面向对象;

public class phone {
    //定义成员变量
    int a, b;

    //定义成员方法
    public void fangfa1(int a, int b) {
        System.out.println("a+b的值为" + (a + b));
    }
}

#####调用类

package 面向对象;

public class Main {
    public static void main(String[] args) {
        //若要使用类,需要先创建对象
        phone p=new phone();
        //调用成员变量并赋值
        p.a=1;
        p.b=2;
        //调用成员变量并打印
        System.out.println(p.a);
        System.out.println(p.b);
        //调用成员方法
        p.fangfa1(p.a,p.b);
    }
}

成员变量与局部变量

成员变量定义在内,成员方法外,成员变量有初始化值,默认为null ,作用范围是整个内,随着对象的创建而存在,随着对象的消失而消失

局部变量定义成员方法中,或者是形式参数无初始化值,作用在方法中,随着方法的调用而存在,随着调用结束而消失

若局部变量与成员变量名称冲突时,采用就近原则,类中的成员变量在声明时可以赋初值

如果直接使用对象名 = 另一个对象名,此时相当于把另一个对象的地址给了这个对象,改变其中一个的值,另一个的值也改变

public class hello {


    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        Person people = new Person();
        people.name= "admin";
        System.out.println(people.name);
        Person p2 = people;
        p2.name = "Microsoft";
        System.out.println(people.name);
    }
}
public class Person {
    String name;
    int age;
    boolean sex;

    public void eat() {
        System.out.println("人会吃饭");
    }
}
//执行结果
//admin
//Microsoft

封装

将功能封装在一块,提供使用的功能,类的对象何以频繁被使用

四种权限(针对变量和方法的)

修饰可用范围
private类内
缺省,不说明权限类内,同一包内
protected类内,同一包内,不同的包的子类
public类内,同一包内,不同的包的子类,同一个工程内

修饰类只能用public或者缺省

好处

提高安全性

提高复用性

复杂事情简单化

####举例

类和方法都体现了封装

写个打印数组的函数并封装到类中,每次执行调用类来打印,也体现了封装

public 是公共的意思,可以在任意类中访问public权限的类

private关键字

私有意思,是一种访问权限修饰符,用来修饰类中的成员

特点是修饰的成员只能在本类中进行访问

语法

private 数据类型 变量名
private 返回值类型 方法名(参数列表)
{
	语句;
}

public一般用来修饰成员变量

private一般用来修饰成员方法

this关键字

意为本类对象的引用,本质也是个对象,可以理解为当前对象

特点:每个普通的函数(方法)都有一个this,谁调用该方法,this就指向谁,方法也可以通过this进行调用,通常都省略,也可以用来修饰构造器

this是为了解决以下(第四行)问题(成员变量和局部变量重名):

public class stu{
    private String name;
    public void setname(String name){
        name = name;//就近原则,此时两个name都为形参name
    }
}

解决:

public class stu{
    private String name;
    public void setname(String name){
        this.name=name;
    }
}

也可以用来减少代码的冗余度

class Animal{
    String name = "没有名字";
    private int weight, height;
    public Animal(){
        System.out.println("无参构造");
    }
    public Animal(int weight, int height){
        this.height = height;
        this.weight = weight;
    }
    public Animal(String name){
        this.name = name;
    }
    public Animal(String name,int height,int weight){
        this.name = name;
        this.height = height;
        this.weight = weight;
    }
}

以上代码中,构造器的冗余部分过多,可以中this进行减少冗余度,此时的this相当于当前对象,即this(参数列表)也相当于一个构造器,不能自己调用当前的构造器

class Animal{
    String name = "没有名字";
    private int weight, height;
    public Animal(){
        System.out.println("无参构造");
    }
    public Animal(int height, int weight){
        this.height = height;
        this.weight = weight;
    }
    public Animal(String name){
        this.name = name;
    }
    public Animal(String name,int height,int weight){
       this(height,weight);//相当于调用的是第7行的this
       this.name = name;
    }
}
用法:
this.属性名;
this.方法名(参数);

构造器

new关键字是用来构造方法的

构造方法是用来初始化对象的

默认的无参构造器的权限与类的权限一致

格式

修饰符 构造方法名(参数列表){
    方法体
}

构造方法时,方法名必须与类名一致,没有返回值但可以写return,也没有返回值类型

注意事项:

  1. 若未构造方法,系统将自动进行无参构造
  2. 若已构造,系统不再构造
  3. 构造方法可以重载

例子

有参构造和无参构造区别

package 面向对象2;
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner ito=new Scanner(System.in);
        stu p=new stu();//属于无参构造
        stu p2=new stu("admin",18);//有参构造
        p2.print();//有参构造,已赋初值
        System.out.println();
        p.print();//无参构造,未赋任何初值
    }
}
package 面向对象2;

public class stu {
    public stu() {   //无参构造
    }

    public stu(String name, int age) {  //为stu的重载,属于有参构造
        this.name = name;
        this.age = age;
    }

    private String name;
    private int age;

    public void setNameAge(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void print() {
        System.out.print("姓名:" + (name) + " 年龄:" + (age));
    }
}

标准的JavaBean类

即Java语言写成的可重用组件

是指符合

  • 类是公共的
  • 有一个无参的公共构造器
  • 有属性,对应get和set方法
public class 类{
    //成员变量,全部使用private修饰
    
    //沟构造函数/方法 分为有参构造和无参构造
    
    //公共的访问方式
}

继承

extends,中文为延长、扩展

概念

  • 让类与类之间产生父子关系
  • 被继承的称为父类(基类、超类、基类),superclass
  • 继承的类称为子类(派生类),subclass
  • 一个类只能有一个父类,不能有多个,所以Java的继承为单继承
  • 允许多层继承
  • 如果没有声明一个类的父类,那么该类默认继承自java.lang.Object类,因此每个类中默认有
  • 父类中的构造器不会直接被继承

方法的重写

在子类中,可以对父类已有的方法进行改造,也成为该方法的重置、覆盖,程序执行时,子类的方法将覆盖父类的方法

  • 方法名和形参列表必须要一样
  • 子类中重写的方法的权限修饰符不小于父类的权限修饰符
  • 子类中不能重写父类中private权限的方法
  • 如果父类的返回值类型为基本数据类型,那么父类被重写的方法和子类中重写的方法的返回值要相同,如果父类的返回值类型是类,父类中返回值的类型时A类,子类中返回值的类型可以写为A类的子类
  • 只有非static的方法可以重写

变量的重写

变量在子类中重写后,使用父类中原有的getter或者setter时,是对父类中的该变量进行赋值,而不是对子类中的重写后的变量进行赋值,属性(变量)在重写后不会覆盖父类中原有的属性,而是作为两个独立存在的属性放到内存中

super关键字

当子类重写父类的方法后,如果还想在子类中调用原来被重写前的方法/变量,可以使用super.关键字调用重写后的父类中的属性/方法

子类中调用与父类中不重名的方法/属性时,直接写方法和属性即可此时等价于super.属性/方法名this.相类似

super也可以去间接父类中寻找

例如c是b的子类,b是a的子类,a中有一个aa方法被c重写了,如果在c中找之前的aa方法,可以直接使用super

super添加形参列表代表调用父类的构造器,即可以使用super(形参列表)调用父类的指定的构造器,在子类的构造器中,this构造器和super构造器只能出现一个,因为Java限制**'super()' 或者 'this' 的调用必须是构造方法的方法体中的第一条语句**,如果构造方法中没有写任何的语句,则默认是调用super()的,即调用空参构造器,视频的7分08秒

如果父类中只有非空参的构造方法,那么子类中,如果子类中写一个新的构造方法时,会报错,因为此时子类中的构造器需要调用super(),此时找不到空参构造方法,为保险起见,最好给每一个类保留一个空参的构造方法

public class test{
    public static void main(String[] args){
        peopleInfo people = new peopleInfo();
        people.getId();
    }
}
class info{
    int id = 1001;
    String name;
}
class peopleInfo{
    int id = 1002;
    public void getId(){
        System.out.println("id = " + id + "superId = " + super.id);//第一个id等价于this.id
    }
}

以上输出结果为id = 1001 superId = 1002

子类中使用父类的构造器

class Animal{
    String name;
    int height, weight;

    public Animal() {

    }

    public Animal(String name, int height, int weight) {
        this.name = name;
        this.height = height;
        this.weight = weight;
    }
}
class Dog{
    public Dog(String name, int height, int weight){
        super(name, height, weight);
    }
}

多态

对象的多态性:用一个父类声明不同的子类,即父类的引用指向子类的对象(子类的对象赋给父类的引用)

//例如Man和Woman是Person的一个子类,
Person people1 = new Man();
Person people2 = new Woman();
此时的体现了这个对象是多种形态

以上方式实例化对象后,只能调用父类中有的方法和属性(如果方法被重写,那就调用重写后的,多态性不适用于属性),不能调用该对象所特有的方法和属性,也就是说 编译时看左边的类型,运行时看右边

有了继承才有多态,还要有方法的重写

使用强制类型转换可以调用子类中特有的方法,又被称为向下转型,要想向下转型,需保证new的是等号左边的一个子类

class Test{
    public static void main(String[] args){
        Animal dog = new Dog();
        //此时的dog对象不能调用shout方法
        
        //向下转型
        Dog dog2 = (Dog) dog;
        //此时的dog2可以调用shout方法
	}
}

class Animal{
    String name;
    public void eat(){
        
    }
    public void drink(){
        
    }
}

class Dog extends Animal{
    public shout(){
        
    }
}

instanceof关键字

中文:实例,读音'ɪnstənsəv

作用:判断一个对象是否是一个类的实例,向下转型时可能会出现异常,为了避免该情况,可以使用instanceof进行判断,不能判断基本数据类型

Animal dog = new Cat();
Dog dog2 = (Dog) dog;//编译会通过,但执行会出现异常,可以使用instanceof进行判断

//修改为
if(dog instanceof Dog){
    Dog dog2 = (Dog) dog;
}

boolean类型

用法:实例变量(对象) instanceof 类名

##abstract关键字

只能用来修饰类和方法,不能修饰私有方法

###抽象类

在类前使用abstract进行修饰,'æbstrækt,抽象的、理论的

有的类不能够被初始化,例如这个类是作为其他多个类的基类时,这个类中仅保存着其他类的共有的属性,即使被初始化,也没有相关的意义,可以用abstract进行修饰限定不可用于初始化一个对象,即不能被new出来

###抽象方法

abstract关键字也可用于方法前,格式为权限修饰符 abstract 返回值 方法名(参数列表);

仅能在抽象类中存在抽象方法,抽象方法不允许有方法体

当继承于含有抽象方法的抽象类时,必须重写覆盖父类中的抽象方法,抽象方法常常作为多态进行使用(因为只能调用父类中有的方法和属性(如果方法被重写,那就调用重写后的,多态性不适用于属性),不能调用该对象所特有的方法和属性),可以看作是函数声明

####格式

class 父类{
    //语句
}

class 子extends 父类{
    //语句
}

继承之后的效果

子类继承父类的非私有成员

Alt+insert快速构造函数(方法)

如果子类中没有重写父类的abstract方法,那么该类也是抽象类

匿名类

有这么一个抽象类

abstract class a{
    int a;
    abstract public void fun1();
}

也可以用来直接创建匿名类

a aaa = new a(){
    public void fun1(){ //此时需要重写覆盖a类中的抽象方法
        
    };
}

如果没有抽象方法,那么必须要随意的覆盖一个方法

Object类

  • 是所有Java类的一个父类
  • 有一个空参构造器
  • 垃圾回收的方法在该类中定义,垃圾回收之前会调用该方法,即finalizeˈfīnlˌīz(敲定)方法

equals()方法

在Java中,==可以判断基本数据类型是否相等,引用类型的地址是否相等,所以,需要```equals()``方法来判断里边的值是否都相等

equals()方法需要自行重写,默认的equals方法中仅能判断地址是否相同(即与==作用相同)

public boolean equals(Object obj) { //默认的equals方法
      return (this == obj);
 }

toString()方法

toString方法重写前默认返回对象的地址,toString()为对象名的默认返回值,即System.out.println(对象名)的内容,与python中的__str__方法作用效果一致

package

中文含义为包,ˈpakij

实现对项目更好的管理,可以使用package声明类或者接口所属的包,声明在源文件首行

同一个包下,不能定义同名的接口或者类

import

导入,使用定义在不同包中的类

import 包名.类名;

导入一个包中所有的类

import 包名.*;

import目的是省下其他包的类名前的包名

假设有以下的包

├─test
│      Animal.java
│      test.java
│
└─test2
        test2.java

test2下的test2类想要使用test下的Animal类创建对象,可以使用语句

test.Animal a = new test.Animal();

也可以使用import进行简化

import test.Animal;//先导入包


Animal b = new Animal();//直接引用

如果导入的类与本包内的类名冲突,则以导入的为准

如果使用多个不同的包,并且重名的类,那么只能写全称,即包名.类名

java.lang.*包默认是导入的

静态importimport static 类.静态变量/方法,仅可导入类的静态方法和变量,使用时,无需再添加类名,不可以滥用,滥用会导致重名!!!

单元测试

用于代码测试使用

生成方式:idea ALT + insert 选择测试

  • 测试的方法的权限必须是public,并且没有返回值,没有形参
  • 添加注解@test并导包
  • 运行此类
  • 如果没有抛出异常,则显示通过测试
  • 在生成的方法名前右键,可以只测试右键的方法

static关键字

中文是静态的

static可以修饰:属性、方法、代码块、内部类

使用static修饰的变量为静态变量,在一个类中,该变量是共享的

非静态变量又称为实例变量

class dog{
    static int a;
}
public class test{
    public static void main(){
        dog test1 = new test();
        test1.a = 999;
        dog test2 = new test();
        test2.a = 888;
    }
}

此时的test1.a = test2.a = 888

  • 静态变量随着类的加载而加载
  • 实例变量随着对象的加载而加载
  • 静态变量的加载早于对象的创建
  • 静态变量存在与方法区中的静态域中,仅加载一次,当加载到方法区中后,无论进行何种操作,都不会离开方法区,除非内存不足或者关掉Java虚拟机
  • 类可以调用直接静态变量、静态方法,不可以调用实例变量(非静态变量)、非静态方法
  • 对象可以调用静态变量、静态方法、实例变量、非静态方法
  • 在一个类中的静态变量前省略的是类名.,而并非this.
  • 静态方法中,只能调用静态的方法和使用静态的变量,不允许使用非静态的方法/变量,也不能使用super、this关键字
  • 非静态方法中,可以任意使用静态或者非静态的方法/变量
  • 构造器不能使用static修饰

main方法的使用

  • 是程序的入口
  • 必须是静态的方法
  • 一个文件中可以有多个main,运行时可以选择需要运行哪个
  • args中有传递的参数

代码块

又被称为初始化块

结构

{
    语句;
}

作用

  • 用来初始化类和对象

  • 可以添加其他修饰符,但只能用static修饰

    static {
        语句;
    }
    
  • 代码块内部可以有输出语句

  • 静态代码块

    • 随着类的加载而执行
      • 当一个类被首次创建时,会执行
      • 当首次执行一个类中的静态方法或者使用静态变量时也会执行
  • 非静态代码块

    • 随着对象的每一次创建而执行,即每创建一次,执行一次
    • 最大的作用是在对象的创建时对属性进行初始化

执行顺序默认初始化->显式初始化->代码块->构造器初始化->对对象中的方法、属性进行操作

final关键字

中文是最后,太监类

可以用来修饰类、对象、方法

  • 修饰类

    • 类前添加final修饰符时,该类无法再被其他类继承了
    • String类、System类都是使用final修饰的
  • 修饰方法

    • 代表这个方法无法被重写了,即同返回值,同参数列表的无法被再次重写,但也可以被重载
    • Object类中的getClass(获取当前对象所属的类)就是final修饰的,无法被重写
  • 修饰变量

    • 修饰后的变量就变成常量了

      • 修饰属性

        • 可以显式初始化,例如final int a = 10;

        • 可以在代码块中赋值

        • 在构造器中赋值,当在一个构造器中赋值时,在其所有的构造器中必须都有赋值语句

          例如

          class a{
              final int b;
              public a(){
                  b = 1; //相当于this.b
              }
              public a(int x){ //允许
                  b = x; //相当于this.b
              }
          }
          
  • 修饰局部变量(局部变量包括:方法体内的变量、形式参数)

    • 当为方法体内的变量时,只能使用显式初始化
    • 当为形式参数时,仅调用函数可赋值,调用后无法在方法体内赋值
  • static final常被称为全局常量

接口interface

中文:端口、接口、界面

Java不支持多继承,使用接口可以实现类似多继承的功能,接口和类是两个并列的结构

接口中不能定义构造器,也就是说,接口不能够被实例化,接口都是通过类来实现的

因为是通过类来实现的,而不是继承,所以使用关键字implements表示,一个类可以实现多个接口

implements中文为实现,ˈɪm.plə.ment

class 类名 implements 接口名1, 接口名2,....., 接口名n{
    
}

如果这个类实现了接口中的所有的抽象方法,那么这个类可以被实例化

如果这个类没有实现接口中的所有的抽象方法,那么这个类一定是抽象类

一个类可以同时继承一个类和实现多个接口

class 类名 extends 类名 implements 接口名1, 接口名2,....., 接口名n{
    
}

JDK 7以及之前只能定义全局常量和抽象方法

全局常量:public static final;修饰
抽象方法:public abstract;修饰

因为有这个限制,所以可以直接省略前边的修饰符,但声明后仍然是全局常量和抽象方法

JDK 8以及之后,除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法

接口和接口之间可以多继承

接口也可以实现匿名类

接口名 变量 = new 接口名(){
    重写接口中的抽象方法;
};

Java8以及以上的接口的特性

JDK 8以及之后,除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法

全局常量:public static final;修饰
抽象方法:public abstract;修饰
静态方法:public static;修饰
默认方法:default;修饰//相当于public default,该方法无需再从实现类中重写,因为已经定义好了
  • 实现类必须重写抽象方法
  • 实现类可以不用重写默认方法
  • 实现类可以调用默认方法
  • 实现类及实例化后的对象不能调用接口中的static方法
  • static方法只能使用接口名.静态方法名调用
  • 如果子类(实现类)中继承的父类和实现的接口中(默认方法)有同名同参数的方法,并且没有在子类(实现类)中重写该方法,那么默认调用的是父类中的该方法
  • 当实现类的多个接口有共同的同名同参数的默认方法,此时必须要在实现类中重写该方法
  • 在实现类中也是可以调用接口中的默认方法,调用方式为接口名.super.方法名()

内部类

Java允许将一个类放到一个类中,外层的类叫做外部类,内层的类叫做内部类

内部类分为成员内部类和局部内部类,局部内部类定义在方法内、代码块内、构造器内

//内部类
class AA{
    public void fun(){
        //局部内部类,方法内
        class BB{
            
        }
    }
    //局部内部类,代码块内
    {
        class CC{
            
        }
    }
    //局部内部类,构造器内
    public AA(){
        class DD{
            
        }
	}
    //成员内部类
    class DD{
        
    }
}

修饰

  • 成员内部类可以用static修饰

    • 当被修饰为静态时,无法调用外层类的非static方法

    • 非静态内部类调用外部类时的方法/属性可以直接写,但此时相当于外部类名.this.方法/属性

  • final修饰,代表无法被继承

  • abstract修饰,代表无法被继承

  • 权限可以有4种,默认、public、private、protect

实例化

  • 静态的内部类

    • 在外部类外(其他类中)
      • 外部类名.内部类名 变量名 = new 外部类名.内部类名()
    • 在外部类中
      • 内部类名 变量名 = new 内部类名()
  • 非静态的内部类

    • 在外部类外(其他类中)

      • 先使用外部类new一个对象,并使用变量引用

      • 外部类名.内部类名 变量名 = 之前new的对象的名字.new 内部类名()
        
      • class AA{
            class BB{
        	}
        }
        
        class OtherClass{
            AA a = new AA();
            AA.BB = a.new BB();
        }
        

Q.E.D.


念念不忘,必有回响。