对象与引用对象
-
对象引用
对于一个简单的例子:
1
Person p=new Person("Jim",18);
内存表示:
栈内存中p并不是一个对象本身,而只是一个指向对象的指针(引用).用等号赋值时,是将右侧堆内存中对象的地址赋予给对象引用.
-
引用赋值
若继续进行操作的话:
Person p2=p; p2.name="Lucy";
那么p的名字也受影响变成了lucy.
2
当我们将一个引用赋值给另一个引用时,我们实际上复制的是对象的地址。两个引用将指向同一对象.其中一个引用修改对象,另一个引用也看得见.
-
垃圾回收
一个对象可以有多个引用,一个引用不可以有多个对象.同时,一个对象要是没有引用,会被垃圾回收.
3
-
参数传递
java只有值传递,java只有值传递,java只有值传递!
如果传递参数类型是基本数据类型,那么传过来的就是这个参数的一个副本,也就是这个原始参数的值,这个与c的传值是一样的。如果在函数中改变了副本的 值不会改变原始的值.
如果传递参数类型是引用类型,那么传过来的就是这个引用参数的副本,这个副本存放的是参数的地址。如果在函数中没有改变这个副本的地址,而是改变了地址中的 值,那么在函数内的改变会影响到传入的参数。如果只是改变地址,指针指来指去,而不去改变值,是不会影响参数的值。
引用一段Clara_babybear代码作为例子:public class ParamTest { public static void main(String[] args){ /** * Test 1: Methods can't modify numeric parameters */ System.out.println("Testing tripleValue:"); double percent = 10; System.out.println("Before: percent=" + percent); tripleValue(percent); System.out.println("After: percent=" + percent); /** * Test 2: Methods can change the state of object parameters */ System.out.println("\nTesting tripleSalary:"); Employee harry = new Employee("Harry", 50000); System.out.println("Before: salary=" + harry.getSalary()); tripleSalary(harry); System.out.println("After: salary=" + harry.getSalary()); /** * Test 3: Methods can't attach new objects to object parameters */ System.out.println("\nTesting swap:"); Employee a = new Employee("Alice", 70000); Employee b = new Employee("Bob", 60000); System.out.println("Before: a=" + a.getName()); System.out.println("Before: b=" + b.getName()); swap(a, b); System.out.println("After: a=" + a.getName()); System.out.println("After: b=" + b.getName()); } private static void swap(Employee x, Employee y) { Employee temp = x; x=y; y=temp; System.out.println("End of method: x=" + x.getName()); System.out.println("End of method: y=" + y.getName()); } private static void tripleSalary(Employee x) { x.raiseSalary(200); System.out.println("End of method: salary=" + x.getSalary()); } private static void tripleValue(double x) { x=3*x; System.out.println("End of Method X= "+x); }
}
输出结果
```java
Testing tripleValue:
Before: percent=10.0
End of Method X= 30.0
After: percent=10.0
Testing tripleSalary:
Before: salary=50000.0
End of method: salary=150000.0
After: salary=150000.0
Testing swap:
Before: a=Alice
Before: b=Bob
End of method: x=Bob //可见引用的副本进行了交换
End of method: y=Alice
After: a=Alice //引用本身没有交换
After: b=Bob
对象内存表示
-
对象内存基础
java中内存主要包含4块,即heap(堆内存)、stack(栈内存)、data segment(静态变量或是常量存放区)、codesegment(方法区).
堆内存: 存放的是new出的对象,new出的对象只包含成员变量.
栈内存: 存放的是局部成员变量。对于基本的数据类型存放的是基本变量的值,而对于对象变量,存放的是堆内存的地址。
静态,常量区: 存放的是静态变量(类变量)或是常量(字符串常量和基本类型常量(public static final))。
方法区: 存放的是对象的方法。因此即使new出多个对象也是只存在一个方法。
对于一段简单的代码:
class Student{
private String name;
private int id;
private Class class;
public void study(){};
}
class Class{
private String name;
private int id;
public void exam(){};
}
public class MainClass(){
public static void main(String[] args){
Student s=new Student();
s.name="Jim";
s.id=001;
s.study();
Student s2=new Student();
s2.name="Lucy"
Class c=new Class();
c.name="三班";
c.id=03;
s.class=c;
c.exam();
}
}
关于该段内存表示:
考虑一些复杂的情况:
class Student{
private String name;
private int id;
private Class class;
public Student(String iname,int iid){
name=iname;
id=iid;
}
public void study(int i){
id=i;
class.exam();
};
}
class Class{
private String name;
private int id;
public void exam(){};
}
public class MainClass(){
public static void main(String[] args){
Student s=new Student("Jim",001);
Class c=new Class();
c.name="三班";
c.id=03;
s.class=c;
s.study(010);
}
}
内存表示:
形参,局部变量基本类型的值都是在栈内存中
-
关于继承与多态内存表示
一个简单的例子:
class Animal(){
private String name;
public void eat(){}
public void run(){
eat();
}
}
class Birds extends Animal(){
private Wing wing;
public void eat(){}
}
public MainClass(){
public static void main(String[] args){
Animal a=new Birds();
a.eat();
a.run();
}
}
6
分析方法调用过程:
创建的对象a指向Birds类,this层为Birds类那层.
a.eat()方法从this层调起,调用Bird类的eat()方法.
a.run()方法从this层调起,没有则去调Animal的run()方法.这时候run()方法要调用eat()方法,同样从this层调起,调用Birds类的eat()方法.
-
串的内存表示
String是一个特殊的包装类数据。可以用
String str = new String("abc");
和String str = "abc";
两种的形式来创建.
第一种用new创建的对象会放在堆中,每调用一次会创建一个新的对象.
第二种先在栈中创建一个对 String类的对象引用变量str,然后通过符号引用去字符串常量池 里找有没有"abc",如果没有,则将"abc"存放进字符串常量池 ,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。
值得一提的是:- new String()和new String("")都是申明一个新的空字符串,是空串不是null;
-
"fredal"=="fre"+"dal";
"fredal"!="fre"+new Stirng("dal");
String s="a";String s2="b";"ab"!=s+s2
- equals对于String简单来说就是比较两字符串的Unicode序列是否相当;而==是比较两字符串的地址是否相同,也就是是否是同一个字符串的引用。
- String是不可变的,所有会产生很多临时变量,可以采用StringBuffer,StringBuilder.
- 关于final,例如
final String ia="a"
,由于对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中或嵌入到它的字节码流中,用的时候ia和"a"没啥区别.2的第三个加了final就是相等的.
-
数组内存表示
首先数组的初始化有静态初始化和动态初始化,前者类似于
String[] names = { "Jim", "Lili", "Lucy" }
这种,后者则是String[] names = new String[4];
这种.
根据数组的存储对象的类型呢也有两种,一种存基本数据类型,一种引用数据类型.
当然还有一维数组和多维数组的区别.
一股脑举个例子:
7String[] names={"Jim", "Lili", "Lucy"}; int [] number=new int[3]; for(int i=1;i<=3;i++){number[i-1]=i} Animal[] animal = new Animal[2]; Animal cat = new Animal("cat", 1); Animal dog = new Animal("dog", 2); animal[0] = dog; animal[1] = cat; int[][] number2=new int[2][]; number2[0]=new int[2]; number2[1]=new int[3];
更多文章与相关下载请看扩展阅读
网友评论