<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>北风技术专栏 &#187; 陈臣</title>
	<atom:link href="http://column.ibeifeng.com/wp-feed.php?author_name=chenchen&#038;feed=feed" rel="self" type="application/rss+xml" />
	<link>http://column.ibeifeng.com</link>
	<description>用技术点亮生活中每个亮点</description>
	<pubDate>Tue, 07 Apr 2009 09:38:07 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.2</generator>
	<language>en</language>
			<item>
		<title>Java类的基本运行顺序</title>
		<link>http://column.ibeifeng.com/chenchen/20081112214.shtml</link>
		<comments>http://column.ibeifeng.com/chenchen/20081112214.shtml#comments</comments>
		<pubDate>Wed, 12 Nov 2008 12:00:06 +0000</pubDate>
		<dc:creator>陈臣</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://column.ibeifeng.com/?p=214</guid>
		<description><![CDATA[作为程序员，应该对自己写的程序具备充分的掌控能力，应该清楚程序的基本运行过程，否则糊里糊涂的，不利于对程序的理解和控制，也不利于技术上的发展。
我们以下面的类来说明一个基本的Java类的运行顺序：


第1行 public class Test {
第2行	private String name = "Java私塾";
第3行	private int age = 2;
第4行	public Test(){
第5行		age = 1000;//期望能到1000年，呵呵
第6行	}
第7行	public static void main(String[] args) {
第8行		Test t = new Test();
第9行		System.out.println(t.name+&#8221;的年龄是&#8221;+t.age+&#8221;年&#8221;);
第10行	}
第11行 }

运行的基本顺序是：
（1）：先运行到第7行，这是程序的入口
（2）：然后运行到第8行，这里要new一个Test，就要调用Test的构造方法
（3）：就运行到第4行，注意：可能很多人觉得接下来就应该运行第5行了，错！初始化一个类，必须先初始化它的属性
（4）：因此运行到第2行，然后是第3行
（5）：属性初始化完过后，才回到构造方法，执行里面的代码，也就是第5行
（6）：然后是第6行，表示new一个Test实例完成
（7）：然后回到main方法中执行第9行
（8）：然后是第10行
运行的结果是：Java私塾的年龄是1000年
说明：这里只是说明一个基本的运行过程，没有考虑更多复杂的情况。
继承中：初始化子类必先初始化父类
有继承的类在运行的时候，一定要记得：初始化子类必先初始化父类，这是Java程序的一个基本运行过程。比如：

第1行public class Test extends Parent{
第2行	private String name = "Java私塾";
第3行	private int age = 2;
第4行	public Test(){
第5行		age = 1000;//期望能到1000年，呵呵
第6行	}
第7行	public static void main(String[] args) {
第8行		Test t = new Test();
第9行		System.out.println(t.name+&#8221;的年龄是&#8221;+t.age+&#8221;年&#8221;);
第10行	}
第11行}
第12行class Parent{
第13行	private int num = 1;
第14行	public [...]]]></description>
			<content:encoded><![CDATA[<p>作为程序员，应该对自己写的程序具备充分的掌控能力，应该清楚程序的基本运行过程，否则糊里糊涂的，不利于对程序的理解和控制，也不利于技术上的发展。</p>
<p>我们以下面的类来说明一个基本的Java类的运行顺序：</p>
<p><span id="more-214"></span></p>
<p><code><br />
第1行 public class Test {<br />
第2行	private String name = "Java私塾";<br />
第3行	private int age = 2;<br />
第4行	public Test(){<br />
第5行		age = 1000;//期望能到1000年，呵呵<br />
第6行	}<br />
第7行	public static void main(String[] args) {<br />
第8行		Test t = new Test();<br />
第9行		System.out.println(t.name+&#8221;的年龄是&#8221;+t.age+&#8221;年&#8221;);<br />
第10行	}<br />
第11行 }<br />
</code></p>
<p>运行的基本顺序是：<br />
（1）：先运行到第7行，这是程序的入口<br />
（2）：然后运行到第8行，这里要new一个Test，就要调用Test的构造方法<br />
（3）：就运行到第4行，注意：可能很多人觉得接下来就应该运行第5行了，错！初始化一个类，必须先初始化它的属性<br />
（4）：因此运行到第2行，然后是第3行<br />
（5）：属性初始化完过后，才回到构造方法，执行里面的代码，也就是第5行<br />
（6）：然后是第6行，表示new一个Test实例完成<br />
（7）：然后回到main方法中执行第9行<br />
（8）：然后是第10行</p>
<p>运行的结果是：Java私塾的年龄是1000年<br />
说明：这里只是说明一个基本的运行过程，没有考虑更多复杂的情况。</p>
<p>继承中：初始化子类必先初始化父类<br />
有继承的类在运行的时候，一定要记得：初始化子类必先初始化父类，这是Java程序的一个基本运行过程。比如：<br />
<code><br />
第1行public class Test extends Parent{<br />
第2行	private String name = "Java私塾";<br />
第3行	private int age = 2;<br />
第4行	public Test(){<br />
第5行		age = 1000;//期望能到1000年，呵呵<br />
第6行	}<br />
第7行	public static void main(String[] args) {<br />
第8行		Test t = new Test();<br />
第9行		System.out.println(t.name+&#8221;的年龄是&#8221;+t.age+&#8221;年&#8221;);<br />
第10行	}<br />
第11行}<br />
第12行class Parent{<br />
第13行	private int num = 1;<br />
第14行	public Parent(){<br />
第15行		System.out.println(&#8221;现在初始化父类&#8221;);<br />
第16行	}<br />
第17行	public void test(){<br />
第18行		System.out.println(&#8221;这是父类的test方法&#8221;);<br />
第19行	}<br />
第20行}<br />
</code></p>
<p>上述类的基本运行顺序是：<br />
（1）：先运行到第7行，这是程序的入口<br />
（2）：然后运行到第8行，这里要new一个Test，就要调用Test的构造方法<br />
（3）：就运行到第4行，注意：初始化子类必先初始化父类<br />
（4）：要先初始化父类，所以运行到第14行<br />
（5）：然后是第13行，初始化一个类，必须先初始化它的属性<br />
（6）：然后是第15行<br />
（7）：然后是第16行，表示父类初始化完成<br />
（8）：然后是回到子类，开始初始化属性，因此运行到第2行，然后是第3行<br />
（9）：子类属性初始化完过后，才回到子类的构造方法，执行里面的代码，也就是第5行<br />
（10）：然后是第6行，表示new一个Test实例完成<br />
（11）：然后回到main方法中执行第9行<br />
（12）：然后是第10行</p>
<p>运行结果是：<br />
现在初始化父类<br />
Java私塾的年龄是1000年</p>
]]></content:encoded>
			<wfw:commentRss>http://column.ibeifeng.com/chenchen/20081112214.shtml/feed</wfw:commentRss>
		</item>
		<item>
		<title>按值传递还是按引用传递</title>
		<link>http://column.ibeifeng.com/chenchen/20081022186.shtml</link>
		<comments>http://column.ibeifeng.com/chenchen/20081022186.shtml#comments</comments>
		<pubDate>Wed, 22 Oct 2008 13:25:51 +0000</pubDate>
		<dc:creator>陈臣</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[传递]]></category>

		<guid isPermaLink="false">http://column.ibeifeng.com/?p=186</guid>
		<description><![CDATA[这个在Java里面是经常被提起的问题，也有一些争论，似乎最后还有一个所谓的结论：“在Java里面参数传递都是按值传递”。事实上，这很容易让人迷惑，下面先分别看看什么是按值传递，什么是按引用传递，只要能正确理解，至于称作按什么传递就不是个大问题了。

1：按值传递是什么
指的是在方法调用时，传递的参数是按值的拷贝传递。示例如下：

public class TempTest {
private void test1(int a){
//做点事情
}
public static void main(String[] args) {
TempTest t = new TempTest();
int a = 3;
t.test1(a);//这里传递的参数a就是按值传递
}
}

按值传递重要特点：传递的是值的拷贝，也就是说传递后就互不相关了。
示例如下：

public class TempTest {
private void test1(int a){
a = 5;
System.out.println("test1方法中的a==="+a);
}
public static void main(String[] args) {
TempTest t = new TempTest();
int a = 3;
t.test1(a);//传递后，test1方法对变量值的改变不影响这里的a
System.out.println(&#8221;main方法中的a===&#8221;+a);
}
}

运行结果是：
test1方法中的a===5
main方法中的a===3
2：按引用传递是什么
指的是在方法调用时，传递的参数是按引用进行传递，其实传递的引用的地址，也就是变量所对应的内存空间的地址。
示例如下：

public class TempTest {
private void test1(A a){
}
public static void main(String[] args) {
TempTest t = new TempTest();
A a [...]]]></description>
			<content:encoded><![CDATA[<p>这个在Java里面是经常被提起的问题，也有一些争论，似乎最后还有一个所谓的结论：“在Java里面参数传递都是按值传递”。事实上，这很容易让人迷惑，下面先分别看看什么是按值传递，什么是按引用传递，只要能正确理解，至于称作按什么传递就不是个大问题了。</p>
<p><span id="more-186"></span></p>
<p><strong>1：按值传递是什么</strong><br />
指的是在方法调用时，传递的参数是按值的拷贝传递。示例如下：<br />
<code><br />
public class TempTest {<br />
private void test1(int a){<br />
//做点事情<br />
}<br />
public static void main(String[] args) {<br />
TempTest t = new TempTest();<br />
int a = 3;<br />
t.test1(a);//这里传递的参数a就是按值传递<br />
}<br />
}<br />
</code><br />
按值传递重要特点：传递的是值的拷贝，也就是说传递后就互不相关了。<br />
示例如下：<br />
<code><br />
public class TempTest {<br />
private void test1(int a){<br />
a = 5;<br />
System.out.println("test1方法中的a==="+a);<br />
}<br />
public static void main(String[] args) {<br />
TempTest t = new TempTest();<br />
int a = 3;<br />
t.test1(a);//传递后，test1方法对变量值的改变不影响这里的a<br />
System.out.println(&#8221;main方法中的a===&#8221;+a);<br />
}<br />
}<br />
</code><br />
运行结果是：<br />
test1方法中的a===5<br />
main方法中的a===3</p>
<p><strong>2：按引用传递是什么</strong><br />
指的是在方法调用时，传递的参数是按引用进行传递，其实传递的引用的地址，也就是变量所对应的内存空间的地址。<br />
示例如下：<br />
<code><br />
public class TempTest {<br />
private void test1(A a){</code></p>
<p>}<br />
public static void main(String[] args) {<br />
TempTest t = new TempTest();<br />
A a = new A();<br />
t.test1(a); //这里传递的参数a就是按引用传递<br />
}<br />
}<br />
class A{<br />
public int age = 0;<br />
}</p>
<p><strong>3：按引用传递的重要特点</strong><br />
传递的是值的引用，也就是说传递前和传递后都指向同一个引用（也就是同一个内存空间）。<br />
示例如下：<br />
<code><br />
第1行 public class TempTest {<br />
第2行	private void test1(A a){<br />
第3行		a.age = 20;<br />
第4行		System.out.println("test1方法中的age="+a.age);<br />
第5行	}<br />
第6行	public static void main(String[] args) {<br />
第7行		TempTest t = new TempTest();<br />
第8行		A a = new A();<br />
第9行		a.age = 10;<br />
第10行		t.test1(a);<br />
第11行		System.out.println(&#8221;main方法中的age=&#8221;+a.age);<br />
第12行	}<br />
第13行 }<br />
第14行 class A{<br />
第15行	public int age = 0;<br />
第16行 }<br />
</code><br />
运行结果如下：<br />
test1方法中的age=20<br />
main方法中的age=20</p>
<p><strong>4：理解按引用传递的过程——内存分配示意图</strong><br />
要想正确理解按引用传递的过程，就必须学会理解内存分配的过程，内存分配示意图可以辅助我们去理解这个过程。<br />
用上面的例子来进行分析：<br />
（1）：运行开始，运行第8行，创建了一个A的实例，内存分配示意如下：</p>
<p><img src="http://column.ibeifeng.com/images/img/2008/10/chenchen-1.jpg" alt="" /></p>
<p>（2）：运行第9行，是修改A实例里面的age的值，运行后内存分配示意如下：</p>
<p><img src="http://column.ibeifeng.com/images/img/2008/10/chenchen-2.jpg" alt="" /></p>
<p>（3）：运行第10行，是把main方法中的变量a所引用的内存空间地址，按引用传递给test1方法中的a变量。请注意：这两个a变量是完全不同的，不要被名称相同所蒙蔽。</p>
<p>内存分配示意如下：</p>
<p><img src="http://column.ibeifeng.com/images/img/2008/10/chenchen-3.jpg" alt="" /></p>
<p>由于是按引用传递，也就是传递的是内存空间的地址，所以传递完成后形成的新的内存示意图如下：</p>
<p><img src="http://column.ibeifeng.com/images/img/2008/10/chenchen-4.jpg" alt="" /><br />
也就是说：是两个变量都指向同一个空间。</p>
<p>（4）：运行第3行，为test1方法中的变量a指向的A实例的age进行赋值，完成后形成的新的内存示意图如下：</p>
<p><img src="http://column.ibeifeng.com/images/img/2008/10/chenchen-5.jpg" alt="" /></p>
<p>此时A实例的age值的变化是由test1方法引起的</p>
<p>（5）：运行第4行，根据此时的内存示意图，输出test1方法中的age=20<br />
（6）：运行第11行，根据此时的内存示意图，输出main方法中的age=20</p>
<p><strong>5：对上述例子的改变</strong><br />
理解了上面的例子，可能有人会问，那么能不能让按照引用传递的值，相互不影响呢？就是test1方法里面的修改不影响到main方法里面呢？<br />
方法是在test1方法里面新new一个实例就可以了。改变成下面的例子，其中第3行为新加的：</p>
<p><code><br />
第1行 public class TempTest {<br />
第2行	private void test1(A a){<br />
第3行		a = new A();//新加的一行<br />
第4行		a.age = 20;<br />
第5行		System.out.println("test1方法中的age="+a.age);<br />
第6行	}<br />
第7行	public static void main(String[] args) {<br />
第8行		TempTest t = new TempTest();<br />
第9行		A a = new A();<br />
第10行		a.age = 10;<br />
第11行		t.test1(a);<br />
第12行		System.out.println(&#8221;main方法中的age=&#8221;+a.age);<br />
第13行	}<br />
第14行}<br />
第15行class A{<br />
第16行	public int age = 0;<br />
第17行}<br />
</code></p>
<p>运行结果为：<br />
test1方法中的age=20<br />
main方法中的age=10</p>
<p>为什么这次的运行结果和前面的例子不一样呢，还是使用内存示意图来理解一下</p>
<p><strong>6：再次理解按引用传递</strong><br />
（1）：运行开始，运行第9行，创建了一个A的实例，内存分配示意如下：<br />
<img src="http://column.ibeifeng.com/images/img/2008/10/chenchen-1.jpg" alt="" /></p>
<p>（2）：运行第10行，是修改A实例里面的age的值，运行后内存分配示意如下：</p>
<p><img src="http://column.ibeifeng.com/images/img/2008/10/chenchen-2.jpg" alt="" /></p>
<p>（3）：运行第11行，是把main方法中的变量a所引用的内存空间地址，按引用传递给test1方法中的a变量。请注意：这两个a变量是完全不同的，不要被名称相同所蒙蔽。</p>
<p>内存分配示意如下：</p>
<p><img src="http://column.ibeifeng.com/images/img/2008/10/chenchen-3.jpg" alt="" /></p>
<p>由于是按引用传递，也就是传递的是内存空间的地址，所以传递完成后形成的新的内存示意图如下：</p>
<p><img src="http://column.ibeifeng.com/images/img/2008/10/chenchen-4.jpg" alt="" /></p>
<p>也就是说：是两个变量都指向同一个空间。</p>
<p>（4）：运行第3行，为test1方法中的变量a重新生成了新的A实例的，完成后形成的新的内存示意图如下：</p>
<p><img src="http://column.ibeifeng.com/images/img/2008/10/chenchen-6.jpg" alt="" /></p>
<p>（5）：运行第4行，为test1方法中的变量a指向的新的A实例的age进行赋值，完成后形成的新的内存示意图如下：</p>
<p><img src="http://column.ibeifeng.com/images/img/2008/10/chenchen-7.jpg" alt="" /></p>
<p>注意：这个时候test1方法中的变量a的age被改变，而main方法中的是没有改变的。</p>
<p>（6）：运行第5行，根据此时的内存示意图，输出test1方法中的age=20<br />
（7）：运行第12行，根据此时的内存示意图，输出main方法中的age=10</p>
<p><strong>7：说明</strong><br />
（1）：“在Java里面参数传递都是按值传递”这句话的意思是：按值传递是传递的值的拷贝，按引用传递其实传递的是引用的地址值，所以统称按值传递。<br />
（2）：在Java里面只有基本类型和按照下面这种定义方式的String是按值传递，其它的都是按引用传递。就是直接使用双引号定义字符串方式：String str = “Java私塾”;</p>
]]></content:encoded>
			<wfw:commentRss>http://column.ibeifeng.com/chenchen/20081022186.shtml/feed</wfw:commentRss>
		</item>
	</channel>
</rss>
