- 浏览: 10031 次
- 性别:
-
文章分类
最新评论
关于java中值的传递与改变
Java中变量有其作用范围,属性(全局变量)在类中都是其作用范围,方法中定义的变量作用范围是方法,方法中的循环中定义的作用范围就只有在此循环中,若其他的方法或类要对这个变量作出改变或使用,则需要用到传值。
Java中传值一般要用到三个方法:建立一个get的方法,通过类名直接访问属性,构造方法传值。
一:建立一个get的方法
Get方法中可以从其他类中或本类中得到返回的值。当然,在本类中要得到一个值没有必要特别建立一个get方法,一般时候只要将这个值设置为属性即可,但注意,静态的方法中只能直接得到静态的变量。看下面的例子。
第1个类:此类是程序的入口
public class GetMethodTran { //建立一个一般属性值 private int j=15; //建立一个静态属性值 private static int k=20; public static void main(String[] args) { Tran t=new Tran(); //从其他类中得到一个整形值 int i=t.getInOtherClass(); System.out.println("从其他类中得到了值:i="+i);
GetMethodTran gmt=new GetMethodTran(); //从本类中得到一个整形值 i=gmt.getInSameClass(); System.out.println("从本类中得到了值:i="+i);
//从本类中得到静态属性值 int a=k; System.out.println("从本类中得到的值:a="+a);
//试图得到一个非静态的属性,会报错,因为程序入口main方法是静态的 //int b=j;
} /** * 建立的一个get方法 * @return 一个整形值 */ public int getInSameClass(){ return 10; } } |
第2个类,只有一个get方法,用于测试
public class Tran { /** * 建立的一个get方法 * @return 一个整形值 */ public int getInOtherClass(){ return 5; } } |
二:通过类名直接访问属性
此方法看似最为简便,那么在其他类中可以访问其他类中什么修饰符修饰下的属性呢?
下面的例子:
第1个类,用于得到别的类中的属性
public class GetAttribute {
public static void main(String[] args) { MyAttributes a=new MyAttributes(); //得到一个默认的属性 int i=a.def; //得到一个受保护的属性 i=a.pro; //得到一个公有的属性 i=a.pub; //得到一个静态默认的属性 i=a.sta; //试图得到一个私有的属性,报错 //i=a.pri;
} } |
第2个类,设置属性,用于测试
public class MyAttributes { //公有属性 public int pub=0; //受保护属性 protected int pro=5; //默认属性,一般认为是default或friendly int def=10; //私有属性 private int pri=15; //静态默认属性 static int sta=20;
} |
在这两个类,我把它们放置在同一个工程的同一个包中,所以才除了私有的属性不能被第一个类访问,当这两个类在不同的包中时会出现不同的结果,原因是java的保护机制,属性的修饰符的原因,修饰符控制了属性的访问范围。此时,了解修饰符很重要。以下是修饰符的简单介绍:
Public :公有,同包或不同的包中的类都可访问,
Protected: 本包中所有类以及包外的子类可访问,
Default/friendly:本包内的所有类可以访问,其他包中类包括子类无法访问,
Private: 只有在类的内部能访问,
当然了,不同的工程中,不管是什么修饰符下的属性也是不可访问的。
三:构造方法传值
此方法最为常用,它有固定的格式。看下面的例子。
第一个类,用于传值,开始程序
public class MyConstruction {
public static void main(String[] args) { int i=5; //实例对象,同时完成了传值 MyConstruction2 mc=new MyConstruction2(i);
}
} |
第二个类,得到第一个类的值,并打印出来
public class MyConstruction2 { private int i; /** * 有参的用于传值的构造方法 * @param i 传来的值 */
public MyConstruction2(int i){ this.i=i; System.out.println("得到传来的值:i="+i); }
} |
当然,构造方法中可以一次传递多个值,这个格式如下:
修饰符 类名(第一个值的类型 第一个值的变量名,第二个值的类型 第二个值的变量名,·····,第N个值的类型 第N个值的变量名){}
在有此类构造方法的类中,一般也设置了1~N个属性,在构造方法中的大括号中有N个“this.变量名=变量名;”,如何理解这个表达式呢。“This.变量名”是指本类中的属性,“=变量名”中的变量名是指构造方法格式中的1~N个变量名的某个,是调用了此个构造方法实例对象时传来的值。格式中“this.变量名=变量名;”这两个变量名不一定相同。
注意,当建立了有参构造方法,原有的无参构造方法将会隐藏,要用无参构造方法的话要在类中重新建立一个无参构造方法。
我们知道,传值的目的是对传来的值作出一些改变,传值方法的传的值也不仅是八种基本的数据类型,还包括了对象。有的时候,我们想传过去的值的改变不影响原来的值,有时却要传过去的值的改变要改变原来的值,来使原来的值产生一些必要的改变,出现新的样式。这就要理解和区别它们。这里主要讨论一下我对八种基本数据类型,数组,对象,String的一些传值改变的理解。
一:关于八种基本数据类型
基本数据类型一般都是值的传递,以int作为例子。
第一个类,程序入口,利用构造方法传值
public class BaseType {
public static void main(String[] args) { //传过去的值是0; int i=0; BaseType2 bt=new BaseType2(i); System.out.println("经过了BaseType2构造方法后的i值:"+i); change(i); System.out.println("执行了change(int i)方法后原来的i值:"+i); } /** * 改变i值的方法 * @param i 传入的数据 */ public static void change(int i){ i=10; System.out.println("执行了change(int i)方法的后来的i值:"+i); }
} |
第二个类,对值进行改变,
public class BaseType2 { private int i; public BaseType2(int i){ this.i=i; System.out.println("BaseType传来的i值:"+i+"\n执行了this.i=i;后的BaseType2的i值:"+this.i); //改变BaseType2的i值 this.i=5; System.out.println("执行了this.i=5;的BaseType2的i值:"+this.i); }
}
|
运行后得到的结果:
由此个例子可看出基本数据类型是通过值进行传递的,当传值后,将此个值赋给别的值A,A的改变不会引起原来的值的改变。
二:对象
关于对象的传值,毫无疑问,是地址的传递,这个关系如下:
我们可以打印这个对象,得到它的内存地址,如此,我们就可以判断出在操作对象传值后出现的改变是否改变了原值。只要地址不变,对这个对象作出的任何操作,都会影响原来的对象。看下面的例子。
第一个类:程序的入口,
public class ObjectTest {
public static void main(String[] args) { ObjectTest2 ot1=new ObjectTest2(20); System.out.println("未调用任何方法进的age="+ot1.age+" 对象内存地址:"+ot1); ot1.setNewAge2(ot1); System.out.println("调用了setNewAge2方法后的age="+ot1.age+" 对象的内存地址:"+ot1); ot1.setNewAge(ot1); System.out.println("调用了setNewAge方法后的age="+ot1.age+" 对象的内存地址:"+ot1); }
} |
第二个类:有两种方法,对传来的对象进行操作,
public class ObjectTest2 { //设置一个年龄属性 public int age; public ObjectTest2(int i){ this.age=i; } /** * 设置一个新的年龄 * @param i 新的年龄 */ private ObjectTest2 ot; public void setNewAge(ObjectTest2 ot){ this.ot=ot; this.ot.age=25; System.out.println("调用了setNewAge方法时的age="+this.ot.age+" 对象的内存地址:"+this.ot); } /** * 设置一个新的年龄 * @param i 新的年龄 */ public void setNewAge2(ObjectTest2 ot){ ot=new ObjectTest2(25); System.out.println("调用了setNewAge2方法时的age="+ot.age+" 对象的内存地址:"+ot); } } |
运行后的结果是:
可以看出,调用setNewAge2方法时,原对象并未发生改变,且输出的对象内存地址不同,意味了setNewAge2方法操作的是不同的两个对象。而setNewAge方法中,使原来的对象发生了改变,setNewAge方法中输出的对象内存地址是原对象的内存地址。其实很容易理解,因为在setNewAge2方法中语句: ot=new ObjectTest2(25);使对象内存地址改变了,所以操作了不同的对象。这里我们称对象的内存地址为对象引用。对于setNewAge方法的对象引用理解是:它们指向了同一个内存地址
对setNewAge2方法的对象引用理解是:它们指向了不同的内存地址
三:数组
关于数组的问题,一般都会问数组是对象还是基本数据类型,因为数组中的元素都是存储八基本数据类型的。一般认为数组是对象,第一,数组的创建使用了new关键字,第二,打印数组的变量名时显示的是内存地址。第三,只是声明而没有创建时,若要使用,必需将其设置为null,而不是其他或它本身就有默认值,可能这是分配内存空间的需要吧。
传递数组时,传递的是对象引用,那么,如果我们要传递后的数组改变不影响原数组怎么办?是否要进行循环,将数组的每个元素分别进行赋值呢。其实不用。看下面的例子。
public class About_ArrayCopy {
/** * @param args */ public static void main(String[] args) { //最后的一个逗号一向不要 int src[]=new int[]{1,2,3,4,5,}; int[] dest=new int[src.length]; //系统的方法,数组的复制 System.arraycopy(src, 0, dest, 0, src.length);
print(src); print(dest); System.out.println(src); System.out.println(dest);
} public static void print(int[] al){ for(int x:al){ System.out.print(x+" "); } System.out.println("\n------------------------"); }
}
|
得到的结果是:
可以看到,数组进行了复制,对象的引用不同。
但有时我们要复制的不是一维数组,而是多维数组怎么做?这个你们可以探究一下。
四:关于String
关于String,我们一定用过很多,这个一般会认为这也是一个基本的数据类型,很简单,因为我们打印变量名时,出现的是String的内容,而不是它的内存地址,而且,它的使用也是和基本数据类型一样,传值时的改变也一样。如下面的例子。
public class AboutString {
public static void main(String[] args) { String str1="abc"; System.out.println("调用changeStr前的str:"+str1); changeStr(str1); System.out.println("调用changeStr后的str:"+str1); } /** * 改变String的方法 * @param str String的传入 */ public static void changeStr(String str){ str=str+"def"; System.out.println("调用changeStr方法时的str:"+str); }
}
|
得到的结果是:
传值的改变规律也如基本数据类型。
但是,其实String是一个类,尽管它与基本数据类型如此相似。如下面的例子。
public class StringTest {
public static void main(String[] args) { //新建一个String对象 String s=new String("String is Class"); System.out.println(s); } } |
但是八种基本数据类明显不能通过new关键字来创建,否则会报错,这个或许能证明String的确是一个类吧。
但是,为什么String表现得如此像基本数据类型呢。因为String是一个非可变类,String对象一旦创建,就不能进行修改,String对象修改后,返回的都是它的新的对象。对此,明显对想用这个String的对象在不同的方法或类中进行修改造成困扰。在这介绍两个String子类用于解决这个问题。StringBuilder和StringBuffer。
如下面的例子。
public class StringTest {
public static void main(String[] args) { //创建StringBuilder对象 StringBuilder stbui=new StringBuilder("StringBuilder"); System.out.println("StringBuilder对象调用方法前:"+stbui); changeStringBuilder(stbui); System.out.println("StringBuilder对象调用方法后:"+stbui);
//创建StringBuffer对象 StringBuffer stbuf=new StringBuffer("StringBuffer"); System.out.println("StringBuffer对象调用方法前:"+stbuf); changeStringBuffer(stbuf); System.out.println("StringBuffer对象调用方法后:"+stbuf); } /** * 改变字符串的方法 1 * @param str 传入的字符串 */ public static void changeStringBuilder(StringBuilder str){ //改变字符串 str=str.append(" will change!"); System.out.println("StringBuilder对象调用方法时:"+str); } /** * 改变字符串的方法 2 * @param str 传入的字符串 */ public static void changeStringBuffer(StringBuffer str){ //改变字符串 str=str.append(" will change too!!"); System.out.println("StringBuffer对象调用方法中:"+str);
} } |
<!--EndFragment-->
相关推荐
Java中值传递和引用传递的区别详解 Java中值传递和引用传递是两个重要的参数传递机制,它们在程序设计中发挥着至关重要的作用。了解这两种机制的区别对于程序员来说是非常必要的。本文将通过示例代码详细介绍Java...
因此,如果在一个方法中改变了这个引用变量指向的对象,原始变量也会受到影响,因为它们都指向同一个堆内存对象。例如,如果你有一个对象`MyClass obj1 = new MyClass();`,然后创建一个新引用`MyClass obj2 = obj1;...
这一点,对于理解Java中值传递的特性至关重要。 在具体讨论基本类型和对象类型时,我们可以看到不同的行为。对于基本类型(如int, double等),它们在栈内存中有具体的值,因此当进行值传递时,这些值被复制到方法...
Python中的参数传递机制与一些其他语言(如C++或Java)中的机制不同,这导致了在传递变量时可能产生一些误解。 首先,我们来解释一下什么是值传递和引用传递。在值传递中,函数接收的是原始数据的一个副本,对这个...
在第一个问题中,涉及到字符串变量`str`的作用域以及Java中值传递与引用传递的概念。Java中,基本数据类型是值传递,而对象(如字符串)则是引用传递。然而,由于字符串在Java中是不可变的,即使在方法中改变了`str`...
这个例子展示了Java中值传递的特点,即使对象的属性在方法内部被修改,原始对象的属性也会受到影响,这是因为传递的是对象引用的副本,而不是对象本身。这种行为与某些其他语言(如C++或C#)中的引用传递不同,后者...
常量是指在程序运行过程中值不会改变的变量。在Java中,常量通常使用`final`关键字声明,以防止值被修改。 示例: ```java public final class Constants { public static final int MAX_SPEED = 200; // 常量 } ...
这个规则解释了为何示例代码的输出是0,而不是1,同时也揭示了Java中值传递和对象引用传递的区别。理解这一点对于编写可靠的异常处理代码至关重要,特别是在处理资源清理(如关闭流)等场景时。
- **arguments**:参数,传递给方法的信息。 - **referenced**:引用,指通过引用变量指向对象。 - **variable**:变量,存储数据的标识符。 - **dimension**:维度,通常指数组的维度。 - **defined**:定义,创建...