认识类与对象
Java是一门面向对象的语言。在面向对象的世界里,一切皆为对象。面向对象是解决问题的⼀种思想,主要依靠对象之间的交互完成一件事情。比如说洗衣服这件事,传统洗衣服有多个步骤:拿盆子,放水,放衣服,放洗衣粉等等。我们注重的是洗衣服的过程,少了一个环节都不行。而且不同衣服种类,清洗的过程都不同。如果将来要洗鞋子,那又是另一种方式。如果用这种方式写代码,将来的维护会很麻烦。而现代洗衣服则很简单,用户不用去关心,只需要将衣服放进洗衣机,倒入洗衣粉,启动开关即可,是通过对象之间的交互来完成的。
那怎么让计算机认识我们定义的一个类呢?类是用来对一个实体(对象)来进行描述的,主要描述该实体(对象)具有哪些属性,哪些功能,描述完成后计算机就可以识别了。
类的定义
一个类由成员变量和成员方法组成,定义狗类举例:
- 定义类使用 class 关键字
- 类名使用英文,格式采用大驼峰
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;
}
}
- this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型
- this只能在"成员方法"中使用
对象的初始化
默认初始化
局部变量必须要初始化才能使用,为什么字段声明之后没有给值依然可以使用?
因为对于成员变量来说,如果没有进行初始化,会有一个对应的默认值
public class Dog {
public String name; //默认初始化为 null
public int age; //默认初始化为 0
}
| 数据类型 | 默认值 |
|---|---|
| byte | 0 |
| char | '\u0000' |
| short | 0 |
| int | 0 |
| long | 0 |
| boolean | false |
| float | 0.0f |
| double | 0 |
| reference | null |
就地初始化
直接赋值
public class Dog {
public int age = 1; //就地初始化为 1
}
构造方法初始化
构造方法是一种特殊的成员方法:
- 名字与类名相同
- 没有返回值类型
- 创建对象时,由编译器自动调用,且在整个对象的生命周期内只调用一次
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;的语句

封装
简单说,就是套壳屏蔽细节,例如下面的代码,成员变量用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());
}
}
}
| 访问限定符的范围 | private | default | protected | public |
|---|---|---|---|---|
| 同一包中的同一类 | ✓ | ✓ | ✓ | ✓ |
| 同一包中的不同类 | ✓ | ✓ | ✓ | |
| 不同包中的子类 | ✓ | ✓ | ||
| 不同包的非子类 | ✓ |
static关键字
用static修饰成员变量称为静态成员变量
- 是一个类固有属性,生命周期伴随类的一生
- 使用类名.静态成员变量名访问
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修饰成员方法称为静态成员方法
- 属于类方法,不属于某个具体的对象
- 通过类名.静态成员方法访问
- 不能在静态方法中调用任何非静态成员变量和非静态成员方法
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";
}
}
