认识类与对象

Java是一门面向对象的语言。在面向对象的世界里,一切皆为对象。面向对象是解决问题的⼀种思想,主要依靠对象之间的交互完成一件事情。比如说洗衣服这件事,传统洗衣服有多个步骤:拿盆子,放水,放衣服,放洗衣粉等等。我们注重的是洗衣服的过程,少了一个环节都不行。而且不同衣服种类,清洗的过程都不同。如果将来要洗鞋子,那又是另一种方式。如果用这种方式写代码,将来的维护会很麻烦。而现代洗衣服则很简单,用户不用去关心,只需要将衣服放进洗衣机,倒入洗衣粉,启动开关即可,是通过对象之间的交互来完成的。

那怎么让计算机认识我们定义的一个类呢?类是用来对一个实体(对象)来进行描述的,主要描述该实体(对象)具有哪些属性,哪些功能,描述完成后计算机就可以识别了。

类的定义

一个类由成员变量和成员方法组成,定义狗类举例:

  1. 定义类使用 class 关键字
  2. 类名使用英文,格式采用大驼峰
public class Dog {

    public String name; //成员变量:名字
    public int age; //成员变量:年龄
    
    public void eat() { //成员方法:吃饭
        System.out.println(name + "吃狗粮");
    }
    
}

由上面的例子看:狗有自己的名字,有年龄,也可以吃的动作。这就是简单的定义了一个类。

类的实例化

定义了一个类,就相当于在计算机中定义了一种新的类型,与int,double类似,只不过这是Java语言自带的内置类型,而类是用户自定义了一个新的类型。有了这些自定义的类型之后,就可以使用这些类来定义对象,这个过程称为类的实例化。

public class Test {

    public static void main(String[] args) {
    
        Dog dog1 = new Dog(); //通过 new 关键字,实例化了一个名为 dog1,类型为 Dog 的对象
        
        Dog dog2 = new Dog(); //通过 new 关键字,实例化了一个名为 dog2,类型为 Dog 的对象
        
    }
    
}

使用类名.成员变量访问对象中的成员。

public class Test {

    public static void main(String[] args) {
    
        Dog dog1 = new Dog();
        dog1.name = "旺财";
        dog1.eat(); //输出:旺财吃狗粮
        
    }
    
}

this关键字

this关键字的使用方法为:this.成员变量 / this.成员方法 / this.构造方法,因此都在自定义的类中使用。
this的引用指向当前对象:

public class Date {

    public int year;
    public int month;
    public int day;

    public void setDay(int year, int month, int day){
        this.year = year; //this.year 代类定义的 year,等号右的 year 指代的是 setDay 方法中的参数
        this.month = month;
        this.day = day;
    }
    
}
  1. this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型
  2. this只能在"成员方法"中使用

对象的初始化

默认初始化

局部变量必须要初始化才能使用,为什么字段声明之后没有给值依然可以使用?
因为对于成员变量来说,如果没有进行初始化,会有一个对应的默认值

public class Dog {

    public String name; //默认初始化为 null
    public int age; //默认初始化为 0
    
}
数据类型默认值
byte0
char'\u0000'
short0
int0
long0
booleanfalse
float0.0f
double0
referencenull

就地初始化

直接赋值

public class Dog {

    public int age = 1; //就地初始化为 1

}

构造方法初始化

构造方法是一种特殊的成员方法:

  1. 名字与类名相同
  2. 没有返回值类型
  3. 创建对象时,由编译器自动调用,且在整个对象的生命周期内只调用一次
public class Date {

    public int year;
    public int month;
    public int day;

    public Date(int year, int month, int day){
        this.year = year;
        this.month = month;
        this.day = day;
        System.out.println("构造方法被调用了")
    }
    
    public static void main(String[] args) {
    
        Date d = new Date(1999,6,9);   //输出:构造方法被调用了
        
    }
    
}

要点1:构造方法可以根据用户的需要提供不同参数的构造方法,形成重载
如果用户没有显式定义构造方法,则编译器会自动提供无参的构造方法,一旦用户提供,则不再生成

public class Date {

    public int year;
    public int month;
    public int day;、
    
    public Date() { //两个Date方法,构成了重载
    
    }
    
    public Date(int year, int month, int day){
        this.year = year;
        this.month = month;
        this.day = day;
    }
   
}

要点2:构造方法中,可以用this.(...)简化代码,且必须为构造方法的第一句,且不能形成环调用

public class Date {
    
    public int year;
    public int month;
    public int day;
    
    public Date() { //调用了三个参数的构造方法
        this(1900, 1, 1);
    } 
    
    public Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }
    
}

对象的打印

如果直接打印对象的引用,得到的值为类路径名@对象的Hashcode值

public class Date {

    public int year;
    public int month;
    public int day;

    public Date(){

    }

    public static void main(String[] args) {
        Date date = new Date();
        System.out.println(date); //输出结果:Date@4eec7777
    }

}

如果想默认打印对象的属性,重写toString方法即可

public class Date {

    public int year;
    public int month;
    public int day;

    public Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    @Override
    public String toString() {
        return "Date{" +
                "year=" + year +
                ", month=" + month +
                ", day=" + day +
                '}';
    }

    public static void main(String[] args) {
        Date date = new Date(1900, 1, 1);
        System.out.println(date); //输出结果:Date{year=1900, month=1, day=1}
    }

}

通俗的来讲就是文件夹,可以防止类名冲突并提高代码可读性

例如我想导入Scanner类,就可以使用java.util.Scanner导入java.util中的Scanner
如果想导入包中的所有类,就使用java.util.*,但实际开发中推荐导入具体的类,否则容易发生冲突的情况。

import java.util.Scanner;

public class Test {

    public static void main(String[] args) {
    
        Scanner scanner = new Scanner(System.in);
        
    }
    
}

自定义包:demo创建在src文件下,则代码中会出现package demo;的语句

WXAVvfl5_1.png

封装

简单说,就是套壳屏蔽细节,例如下面的代码,成员变量用private修饰

public class Student {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static class Test {

        public static void main(String[] args) {
            Student student = new Student();
            student.setName("张三"); //只能手动提供 get 和 set 方法来对外开放
            System.out.println(student.getName());
        }
    }
}
访问限定符的范围privatedefaultprotectedpublic
同一包中的同一类
同一包中的不同类
不同包中的子类
不同包的非子类

static关键字

用static修饰成员变量称为静态成员变量

  1. 是一个类固有属性,生命周期伴随类的一生
  2. 使用类名.静态成员变量名访问
public class Class{

    public static String name;

    public static void main(String[] args) {
        Class.name = "Financial Management 242";
        System.out.println(Class.name); //输出结果:Financial Management 242
    }
    
}

用static修饰成员方法称为静态成员方法

  1. 属于类方法,不属于某个具体的对象
  2. 通过类名.静态成员方法访问
  3. 不能在静态方法中调用任何非静态成员变量和非静态成员方法
public class Class {

    public static String name = "Financial Management 242";

    public static String className() { //静态成员方法
        return "Financial Management 242";
    }

    public static void main(String[] args) {
        System.out.println(Class.className()); //通过类名.静态成员方法访问
    }
}

static成员变量初始化

(1)就地初始化

public class Class {

    public static String name = "Financial Management 242";

    public static void main(String[] args) {
        System.out.println(Class.name); //输出结果:Financial Management 242
    }
    
}

(2)代码块初始化

代码块

使用{}定义的叫做代码块,分为普通代码块,静态代码块,实例代码块和同步代码块

普通代码块

定义在方法中的代码块,变量的生命周期在大括号范围内

public class Test {

    public static void main(String[] args) {
        {
            int a = 10; 
        } 
    }
}

静态代码块

使用static修饰的代码块是静态代码块,一般用于静态变量的初始化

public class Animal {

    public static String name;

    static {
        name = "animal";
    }

}

实例代码块

实例代码块一般用于成员变量的初始化

public class Animal {

    public String name;

    {
        this.name = "animal";
    }

}