java面向对象 + 内存解析
这篇博客主要是重点讲解一些内存和一些规定的解释,对于定义我不会过多赘述,没有Java基础的话可以去翻看我之前的博客,学习完成之后再进行阅读。
面向对象可以说是Java中最重要的一部分了,这次复习我发现有几个点比较重要,这里分享给大家
引入:
小明今天想要一辆玩具车,他获取这辆玩具车有两个选择
1、自己准备,轮子,车架,电池等等原料进行拼接,然后组装起来就成了。
2、直接淘宝买一辆
这就是区别所在,如果选择方案一的话,你需要一步一步的完成这辆车,你需要做很多重复性的工作,组装,填充,打磨等等,但是我只是想要这辆车,我并不会组装怎么办呢?这时可以选择第二种方案直接买一辆。你只需要三个动作,淘宝搜索->选中购买->支付。是不是方便了很多?
面向对象就是说,我们不需要直到这个功能怎么实现的,正如我可以不知道玩具车怎么组装的但是并不妨碍我们使用他。只需要知道用的时候进行调用已封装好的方法即可。
代码实现
定义类:
类是一种用户自定义的数据类型,它包含了数据(属性)和操作数据的方法(行为)。通过定义类,我们可以创建具有相似特征和行为的对象(实例)。
以下是Java中类的一些关键概念:
public class Car {
// 属性
String brand;
int year;
// 方法
public void start() {
System.out.println("The car is starting...");
}
public void stop() {
System.out.println("The car is stopping...");
}
}
创建对象:
对象的创建:通过类定义,我们可以创建一个或多个具有相同属性和方法的对象。对象是类的实例。例如:
public class Main {
public static void main(String[] args) {
// 创建Car类的对象
Car car1 = new Car();
Car car2 = new Car();
}
}
-
属性:属性是类中的变量,用于存储对象的状态。在上述示例中,
brand
和year
是Car
类的属性。 -
方法:方法是类中的函数,用于描述对象的行为。在上述示例中,
start()
和stop()
是Car
类的方法。 -
访问修饰符:Java中的访问修饰符用于控制类、属性和方法的可见性。常见的访问修饰符有:
public
(公共的,无限制访问)、private
(私有的,仅在类内部访问)和protected
(受保护的,仅在类及其子类中访问)。
构造函数:构造函数是一种特殊的方法,用于在创建对象时初始化对象的属性。构造函数的名称与类名相同,且没有返回类型。例如:
public class Car {
String brand;
int year;
// 构造函数
public Car(String brand, int year) {
this.brand = brand;
this.year = year;
}
}
举例:
现在我们举一个基本的例子,我想要定义一个规定人的类,这个类有着唱歌,吃饭的方法。那么我应该怎么定义呢?
public class Person {
String name ;
int age;
String gender;
public Person(){
}
public Person(String name,int age,String gender){
this.age = age;
this.gender = gender;
this.name = name;
}
public void sing(){
System.out.println(this.name+"唱歌");
}
public void dance(){
System.out.println(this.name+"跳舞");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
", gender='" + gender + '\'' +
'}';
}
}
使用这个类创建1个叫张三的人和1个叫李四的人。那么我们根据上面知识进行构造函数的调用。得到两个对象 lisi zhangsan 此时我们执行各自的sing和dance方法
class Main{
public static void main(String[] args) {
Person zhangsan = new Person("张三",18,"男");
Person lisi = new Person("李四",18,"女");
zhangsan.sing();
zhangsan.dance();
lisi.sing();
lisi.dance();
}
}
得到结果
new 关键字的作用是调用构造方法
这个过程由虚拟机调用不需要手动调用,每创建一次对象,就会调用一次构造方法。
new关键字用于创建对象,它会在堆内存中分配一块空间来存放新创建的对象,并返回一个指向该对象的引用。
构造方法是一种特殊的方法,它与类同名且没有返回值,主要用于对象的初始化工作。
过程中的内存讲解
使用new关键字创建对象是将对象创建在堆中的,main方法中的zhangsan lisi是在栈中创建的,之所以可以调用zhangsan.sing()和lisi.sing()是因为,调用new Person()创建完成之后,会返回一个指向堆区中创建的这个对象信息的地址,将这个地址赋值给zhangsan lisi,此时就可以调用储存在堆中的属性和方法了
关系图:zhangsan.sing() === 001.sing()
zhangsan === 001
创建一个对象的过程:
栈分析和垃圾回收:
在栈中,当main()方法加载的时候,此时main()方法进栈,进栈之后,在main方法中zhangsan lisi 被创建,两个变量进入main中。 此时zhangsan.sing()调用,sing()方法进栈,调用结束后后出栈,同理main()方法调用结束出栈。
垃圾回收:当main方法出栈之后,此时zhangsan lisi已经被销毁,堆区中的001内存 和002 内存没有任何变量指向,无法再被访问,此时jvm自动进行垃圾回收。
就近原则
了解完上面的栈操作,我们可以解释一下为什么变量调用遵循就近原则
在Java中,每当定义一个新的作用域(比如一个代码块、方法或者类),都会创建一个新的栈帧(stack frame)。栈帧是用来存储局部变量和方法调用相关信息的内存区域。
当程序执行到一个新的作用域时,会将该作用域中的局部变量和方法参数添加到栈帧中。当程序离开该作用域时,栈帧会被弹出,局部变量和方法参数也会被销毁。
由于栈的工作方式是"后进先出"(LIFO,Last-In-First-Out),所以在同一个作用域中,最后定义的变量会被放在栈的顶部,也就是离栈顶最近的位置。因此,当我们在同一个作用域中使用一个变量时,就近原则会选择离栈顶最近的那个变量。
这样设计的好处是可以有效地管理变量的生命周期,并且保证变量在正确的作用域内使用。同时,也减少了命名冲突的可能性,提高了代码的可读性和维护性。
this关键字的本质
this关键字本质上就是创建的堆空间的地址他的值就是返回给main中接受的变量如zhangsan lisi。
所以使用this关键字调用的方法就是对象的方法,调用的变量就是对象的属性。
public void sing(){
System.out.println(this.name);
this.dance();
System.out.println(this.name+"唱歌");
}