文章目录
一. 面向过程和面向对象
- 面向对象:强调通过对象之间的信息交互,彼此协作去解决问题。
- 面相过程:强调解决问题的过程,把问题看做是一个函数或一组函数的集合,然后使用这些函数对数据进行操作。
二. 类的定义和实例化
1. 类的基本认识
类是实体的抽象,主要描述该实体具有哪些属性(外观尺寸等)、哪些功能(用来干啥),描述完成后就可以用来供计算机识别了。
比如:人,在 Java 中可以将其看成是一个类
属性:名字、性别、年龄、身高、体重…
功能:吃饭、睡觉、打豆豆…
2. 定义一个类
在 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("睡觉");
}
}
注意事项
- 类名注意采用大驼峰定义
- 一般一个文件当中只定义一个类
- public修饰的类必须要和文件名相同
- main方法所在的类一般要使用public修饰(注意:Eclipse默认会在public修饰的类中找main方法)
- 不要轻易去修改public修饰的类的名称,如果要修改,通过开发工具把文件名也一同修改
3. 类的实例化
声明了一个类,就相当于在计算机中声明了一种新的类型,与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
三. 类对象在内存中的存储
1. 实例化对象的内存布局
2. println 打印对象
我们知道需要通过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引用
1. 什么是this引用?
this表示的是当前对象本身,确切地说,this代表了当前对象的一个引用。对象的引用可以理解为对象的另一个名宇,通过引用可以顺利地访问对象。在Java中,this既可以引用当前对象中的成员变量,也可以引用当前对象中的成员方法。
this引用的本质
this引用指向当前对象(即成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过this引用去访问的。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
this是成员方法的第一个隐藏参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员方法的第一个参数this
2. 为什么要有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;
}
3. this的使用场景
this的三种用法:
- this.data,访问当前对象的成员变量
- this.func(…) ,访问当前对象的成员方法
- this(…) ,访问当前对象的构造方法
3.1 访问当前对象的成员变量
class Person{
public String name;
public void setName(String name){
// 通过this访问自己的成员变量name
this.name = name;
}
}
3.2 访问当前对象的成员方法
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()
3.3 访问当前对象的构造方法
注意以下几点:
- 只能在构造方法内使用
- 只能放在构造方法的第一行
- 不能成环
代码示例:
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)
4. this引用的特征
- 有的书上说this代表当前对象,其实这样的说法并不准确。正确的说法应该是:this表示当前对象引用
- this不可以访问静态的成员变量,因为静态成员变量是属于类的
- 同样的静态方法的内部也是不能使用this的,静态方法的第一个参数不会默认传this
五. 构造方法
1. 相关概念
构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在对象的整个生命周期内只调用一次。
代码示例:
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负责开辟好了的。
2. 构造方法的特性
① 名字必须与类名相同
② 没有返回值类型,设置为void也不行
③ 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
④ 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)
⑤ 如果用户没有显式定义构造方法,则编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的
⑥ 构造方法中,可以通过this调用其他构造方法来简化代码
注意:
- this(…)必须是构造方法中第一条语句
- 不能形成环
3. 就地初始化
在成员变量声明的时候,就直接给它赋初始值
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
背后原理:代码编译完成后,编译器会将所有给成员初始化的这些语句添加到各个构造函数中。
4. new 关键字背后所发生的一些事情
Date d = new Date(2023,6,1);
在程序层面只是简单的一条语句,在JVM层面需要做好多事情,下面简单介绍下:
- 检测对象对应的类是否加载了,如果没有加载则加载
- 为对象分配内存空间
- 处理并发安全问题
比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突 - 初始化所分配的空间
即:对象空间被申请好之后,对象中包含的成员会被设置初始值
数据类型 | 默认值 |
---|---|
byte | 0 |
char | ‘\u0000’ |
short | 0 |
int | 0 |
long | 0L |
boolean | false |
float | 0.0f |
double | 0.0 |
reference | null |
-
设置对象头信息
-
调用构造方法,给对象中各个成员赋值