面向对象三大特征
- 继承
- 封装
- 多态
类与对象
类是某一类事务的共同点的抽象概念,而对象描述的是一个具体的产物。
类一般会有2个组成部分
- 属性
- 方法
定义个简单的类
/**
* 类:人
*/
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void tell() {
System.out.println("i am " + name + "and my age is " + age);
}
}
对象的内存引用
在java中,类是属于引用数据类型(非基本数据类型),引用数据类型的掌握难在于要对内存进行管理。
内存空间分为:
- 堆内存(heap)
保存的是对象的具体信息。堆内存的开辟是通过new关键字进行对象的创建。 - 栈内存(stack)
保存的是一块堆内存的地址,即对于堆内存的引用。
引用数据类型也意味着多个栈内存可以指向同一个堆内存,每个栈内存也可以更改指向。
思考如下代码
package com.base.demo;
public class JavaRamDemo {
public static void main(String[] args) {
Person p1 = new Person();
p1.setName("p1");
p1.setAge(22);
changeName(p1.getName());
p1.tell();// i am p1 and my age is 22
changeName(p1);
p1.tell();// i am scott and my age is 22
}
public static void changeName(String name) {
name = "scott";
}
public static void changeName(Person p) {
p.setName("scott");
}
}
为什么都是修改name,但是只有参数为Person的方法起了作用?
因为Java中,方法的参数是对象时,进行了引用传递。而如果方法的入参是基本数据类型时,进行的时值传递。
- 值传递,其实传递的只是实参的副本,那么不论函数中对这个副本做任何改变都不会影响实参的值。
- 引用传递,可以理解为传递的是对象的引用地址。即形参指向的是实参的内存地址。那么修改对应内存地址中的值,便会影响到实参。
新建如下方法
public static void changeNameForNewPerson(Person p) {
p.setName("smith");
p = new Person();
p.setName("new smith");
}
然后再进行调用
changeNameForNewPerson(p1);
p1.tell();//i am smith and my age is 22
为什么此时输出的姓名不是“new smith”?
此时是由于函数中使用new关键字开辟了一个新的内存空间,那么此时形参的内存地址指向便更改了,所以再对其进行操作便不会影响之前传入的实参的值。