类是实体的抽象,主要描述该实体具有哪些属性(外观尺寸等)、哪些功能(用来干啥),描述完成后就可以用来供计算机识别了。
比如:人,在 Java 中可以将其看成是一个类
属性:名字、性别、年龄、身高、体重…
功能:吃饭、睡觉、打豆豆…
在 java 中定义类时需要用到class关键字,具体语法如下:
class为定义类的关键字,ClassName为类的名字(采用大驼峰),{}中为类的主体。
类中包含的内容称为类的成员:
// 创建类
class ClassName{
field; // 字段(属性) 或者 成员变量
method;// 行为 或者 成员方法
} // 最后不用加分号
下面我们声明人这个类:
class People{
// 成员变量
public String _name;
public String _sex;
public int _age;
// 成员函数
public void eat() {
System.out.println("吃饭");
}
public void sleep() {
System.out.println("睡觉");
}
}
注意事项
声明了一个类,就相当于在计算机中声明了一种新的类型,与int,double类似,只不过int和double是java语言自带的内置类型,而类是用户自己声明的一个新类型。
有了这些自己声明的类型之后,就可以使用它们来定义实例(或者称为对象)。用类类型创建对象的过程,称为类的实例化,在java中采用new关键字,配合类名来实例化出对象:
class People{
public String _name;
public String _sex;
public int _age;
public void eat() {
System.out.println("吃饭");
}
public void sleep() {
System.out.println("睡觉");
}
}
public class Test {
public static void main(String[] args) {
// 实例化出一个People类对象
People ps = new People();
ps.eat();
ps.sleep();
}
}
-------运行结果-------
吃饭
睡觉
注意事项
new
关键字用于创建一个对象.
来访问对象中的属性和方法匿名对象
没有引用的对象称为匿名对象,匿名对象只能在创建对象时使用。如果一个对象只是用一次,后面不需要用了,可以考虑使用匿名对象:
class A{
void show(){
System.out.println("hello world");
}
}
public class Test {
public static void main(String[] args) {
new A().show();
}
}
-------运行结果-------
hello world
我们知道需要通过new实例化对象的类型都是引用类型,比如Arrays和String等。此外我们自定义的类也属于引用类型,直接打印类对象的结果是:类名@地址
class People{
public String _name;
public String _sex;
public int _age;
public void Eat() {
System.out.println("吃饭");
}
public void Sleep() {
System.out.println("睡觉");
}
}
public class Test {
public static void main(String[] args) {
People ps = new People();
System.out.println(ps);
}
}
-------运行结果-------
People@1b6d3586
我们发现这里打印出来的是一个地址,这里在打印的时候会默认调用Object 的 toString 方法来打印
既然会默认调用 Object 的 toString 方法,那么如果我们在当前类中重新实现 toString 这个方法后,就会调用当前类重新写的这个 toString 方法来打印。
补充:IDEA快速生成 Object 的 toString 方法快捷键:alt+insert
再来看一段在类中重写 toString 方法后的代码:
class People{
public String _name;
public String _sex;
public int _age;
// @ 在 Java 中称为 “注解”
// 此处的 @Override 表示下面实现的
// toString 方法是重写了父类的方法
@Override
public String toString() {
return "People{" +
"_name='" + _name + '\'' +
", _sex='" + _sex + '\'' +
", _age=" + _age +
'}';
}
}
public class Test {
public static void main(String[] args) {
People ps = new People();
System.out.println(ps);
}
}
-------运行结果-------
People{_name='null', _sex='null', _age=0}
总结:当我们的类没有重写 toString 方法的时候,打印函数就会默认调用Object 的 toString 方法来打印类对象。
this表示的是当前对象本身,确切地说,this代表了当前对象的一个引用。对象的引用可以理解为对象的另一个名宇,通过引用可以顺利地访问对象。在Java中,this既可以引用当前对象中的成员变量,也可以引用当前对象中的成员方法。
this引用的本质
this引用指向当前对象(即成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过this引用去访问的。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
this是成员方法的第一个隐藏参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员方法的第一个参数this
this引用就是使当前对象作为变量指代将来任何一个代表本类对象的实例,使得编程能力大增。这和自然语言中的“这个”、“那个”具有同样的意思,通过指代,使得语言简洁,也具有灵活性。
来看一段代码,通过调用setName,我们想修改成员变量name的值:
class People{
private String name ;
private int age;
public void setName(String name){
name = name;
}
public String getName(){
return name;
}
}
public class Test {
public static void main(String[] args) {
People p = new People();
// 修改名字
p.setName("张三");
// 打印名字
System.out.println(p.getName());
}
}
-------运行结果-------
null
这里传过去的明明是张三,而且也赋值了,为什么打印出来的却是null呢?因为函数中的赋值语句是name = name,成员变量的名字和形参的冲突了,这时局部变量优先,相当于形参自己给自己赋值。
对此我们只需要加一个 this 标明成员变量即可:
public void setName(String name){
this.name = name;
}
this的三种用法:
class Person{
public String name;
public void setName(String name){
// 通过this访问自己的成员变量name
this.name = name;
}
}
class Person{
public String name;
public void show(){
System.out.println("调用了show()");
}
public void setName(String name) {
this.name = name;
// 调用方法时不加this也行,后续编译器会自动加
this.show();
}
}
public class Test {
public static void main(String[] args) {
new Person().setName("张三");
}
}
-------运行结果-------
调用了show()
注意以下几点:
代码示例:
class Person{
public String name;
public Person(String name) {
this.name = name;
System.out.println("Person(String name)");
}
public Person(){
//System.out.println(year); 注释取消掉,编译会失败
this("张三");
}
}
public class Test {
public static void main(String[] args) {
Person ps = new Person();
}
}
-------运行结果-------
Person(String name)
构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在对象的整个生命周期内只调用一次。
代码示例:
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("调用了Date(int, int, int)");
}
}
public class Test {
public static void main(String[] args) {
// 这里仅仅实例化了一个Date类对象
new Date(2023, 6, 1);
}
}
-------运行结果-------
调用了Date(int, int, int)
注意:构造方法的作用就是仅仅是对对象中的成员进行初始化,并不负责给对象开辟空间。而且在初始化之前所需空间已经是由JVM负责开辟好了的。
① 名字必须与类名相同
② 没有返回值类型,设置为void也不行
③ 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
④ 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)
⑤ 如果用户没有显式定义构造方法,则编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的
注意:
在成员变量声明的时候,就直接给它赋初始值
class Date{
public int year = 2023;
public int month = 6;
public int day = 1;
public void show(){
System.out.println(year + "." + month + "." + day);
}
}
public class Test {
public static void main(String[] args) {
new Date().show();
}
}
-------运行结果-------
2023.6.1
背后原理:代码编译完成后,编译器会将所有给成员初始化的这些语句添加到各个构造函数中。
Date d = new Date(2023,6,1);
在程序层面只是简单的一条语句,在JVM层面需要做好多事情,下面简单介绍下:
数据类型 | 默认值 |
---|---|
byte | 0 |
char | ‘\u0000’ |
short | 0 |
int | 0 |
long | 0L |
boolean | false |
float | 0.0f |
double | 0.0 |
reference | null |
设置对象头信息
调用构造方法,给对象中各个成员赋值