技术周总结10.28~11.03 周日
文章目录
- 一、10.30 周三
- 1.1)问题01:一个Java对象的属性被定义变量后,这个变量再被修改为别的值,则原java对象的这个属性值也会变化吗?
- 1.2)问题02:Java函数的入参是一个 引用对象,比如是一个布尔对象Boolean,在函数内部修改这个变量的值,会导致 函数外的这个引用对象的布尔对象 Boolean发生变化吗?
- 1.3)问题03:Java中哪些是可变的引用类型,哪些是不可变的引用类型?
- 1.4) 问题04: 不可变引用类型的例子
- 1.5)问题05: Java中引用变量赋值和引用变量修改的区别
一、10.30 周三
1.1)问题01:一个Java对象的属性被定义变量后,这个变量再被修改为别的值,则原java对象的这个属性值也会变化吗?
在Java中,对象的属性(成员变量)的行为取决于属性的数据类型:
-
基本数据类型(如 int, double, float, boolean 等)是按值传递的。当你将一个对象的基本类型属性赋值给另一个变量时,实际上是将值的副本赋给了那个变量。修改这个新变量不会影响原对象的属性值。
-
引用数据类型(如数组、类对象等)是按引用传递的。当你将一个对象的引用类型属性赋值给另一个变量时,实际上是将属性的引用(即内存地址)赋给了那个变量。如果通过这个新变量修改了对象内的数据,那么原对象的相应属性也会被修改,因为它们指向的是同一块内存地址。
下面是一个简单的例子来说明这一点:
public class Example {int number; // 基本数据类型Integer[] array; // 引用数据类型public static void main(String[] args) {Example obj = new Example();obj.number = 10;obj.array = new Integer[1];obj.array[0] = 100;// 基本数据类型的测试int copyNumber = obj.number;copyNumber = 20; // 修改副本// 引用数据类型的测试Integer[] copyArray = obj.array;copyArray[0] = 200; // 修改引用指向的对象System.out.println(obj.number); // 输出 10,因为基本数据类型的值没有改变System.out.println(obj.array[0]); // 输出 200,因为引用类型的对象已经被修改了}
}
在这个例子中,修改了 copyNumber
并不会改变 obj.number
,因为它是基本数据类型。但是修改 copyArray[0]
会改变 obj.array[0]
,因为它们都指向同一个数组对象。
1.2)问题02:Java函数的入参是一个 引用对象,比如是一个布尔对象Boolean,在函数内部修改这个变量的值,会导致 函数外的这个引用对象的布尔对象 Boolean发生变化吗?
在Java中,Boolean
类型是一个不可变的引用类型。这意味着一旦一个 Boolean
对象被创建,它的值就不能被改变。如果你尝试在一个方法内部修改一个 Boolean
对象的值,实际上你会创建一个新的 Boolean
对象,而原始的 Boolean
对象不会被修改。
要理解这一点,关键是要记住:方法参数是按值传递的。当一个对象实例传递给一个方法时,传递的是对象引用的副本,而不是对象本身。对于不可变对象,这意味着你不能改变原始对象,但是你可以改变持有对象引用副本的变量,使其指向一个新的对象。
下面是一个例子来说明这个概念:
public class TestBoolean {public static void main(String[] args) {Boolean originalValue = Boolean.FALSE;System.out.println("Before method call: " + originalValue); // 输出 falsechangeValue(originalValue);System.out.println("After method call: " + originalValue); // 依然输出 false}public static void changeValue(Boolean value) {value = Boolean.TRUE;}
}
在这个例子中,尽管在changeValue
方法内部尝试将value
设置为Boolean.TRUE
,originalValue
的值并没有改变。这是因为value
是originalValue
的一个引用副本,修改value
引用的变量让它指向了一个新的Boolean
对象,而originalValue
仍然指向原来的Boolean.FALSE
对象。
如果你需要在方法内部修改一个引用类型的对象,并希望这些修改反映到方法外部,你需要确保操作的是可变对象。对于布尔值,通常的做法是使用一个包含布尔字段的可变类,比如下面BooleanWrapper
类的例子。
public class BooleanWrapper {public boolean value;public BooleanWrapper(boolean value) {this.value = value;}
}public class Test {public static void main(String[] args) {BooleanWrapper originalValue = new BooleanWrapper(false);System.out.println("Before method call: " + originalValue.value); // 输出 falsechangeValue(originalValue);System.out.println("After method call: " + originalValue.value); // 输出 true}public static void changeValue(BooleanWrapper valueWrapper) {valueWrapper.value = true;}
}
1.3)问题03:Java中哪些是可变的引用类型,哪些是不可变的引用类型?
在Java中,对象的可变性是由其类的设计决定的。以下是一些常见的不可变和可变引用类型的例子:
不可变的引用类型:
-
基本数据类型的包装类:所有的基本数据类型的包装类都是不可变的。这包括:
Integer
Long
Byte
Short
Float
Double
Character
Boolean
-
String:
String
类在Java中是不可变的。一旦创建了一个String对象,就不能更改它的内容。 -
BigInteger 和 BigDecimal:这些类用于表示大的整数和十进制数,它们也是不可变的。
-
其他不可变类:许多来自Java标准库的类是设计为不可变的,例如
Path
类、Locale
类等。
可变的引用类型:
-
集合类:大部分的Java集合类都是可变的,例如:
ArrayList
LinkedList
HashSet
TreeSet
HashMap
TreeMap
- 等等
-
StringBuilder 和 StringBuffer:这些类是
String
的可变对应类,主要用于在需要频繁修改字符串内容时使用。 -
Java Beans 和 POJOs:通常自定义的类,除非特别设计为不可变,否则它们是可变的。这包括Java Beans和普通的Java对象(POJOs)。
-
日期和时间类:在Java 8之前,日期和时间的API(如
java.util.Date
和java.util.Calendar
)是可变的。然而,在Java 8及以后的版本中,引入了新的日期和时间API(如LocalDate
、LocalTime
和LocalDateTime
),它们是不可变的。 -
数组:所有数组类型(无论是基本数据类型还是对象数组)都是可变的。你可以更改数组中的元素,但不能更改数组的大小。
理解一个类是否可变通常需要查看其API文档。如果一个类没有提供修改其状态的方法,或者文档明确说明它是不可变的,那么它就是不可变的。相反,如果一个类提供了可以改变其状态的方法(比如setter方法),那么它就是可变的。设计不可变类的一个关键特点是它们通常不提供修改对象状态的方法,并且它们的所有字段都是final
的。
1.4) 问题04: 不可变引用类型的例子
下面代码的运行情况怎样?
public class BooleanWrapper {public Boolean value;public BooleanWrapper(boolean value) {this.value = value;}
}public class Test {public static void main(String[] args) {BooleanWrapper originalValue = new BooleanWrapper(false);Boolean value = originalValue.value;value = true;System.out.println("After method call: " + originalValue.value); }}
在这个代码示例中,BooleanWrapper
类的 value
字段是一个 Boolean
对象(引用类型),而不是 boolean
基本数据类型。在 main
方法中,创建了一个 BooleanWrapper
实例 originalValue
,并将其 value
字段初始化为包装了基本数据类型 false
的 Boolean
对象。
然后,声明了一个 Boolean
类型的变量 value
并将 originalValue.value
的引用赋给了它。接着,value
被设置为 true
。这里的关键点是,value
是一个 Boolean
类型的变量,它现在指向一个新的 Boolean
对象 true
,但这个操作并不影响 originalValue
对象的 value
字段,因为 Boolean
是不可变的,你不能通过 value
变量改变 originalValue.value
所引用的 Boolean
对象的内部状态。
由于 originalValue.value
和 value
是两个独立的引用,它们最初指向同一个 Boolean
对象(包装了 false
),但在 value = true;
这行代码之后,value
变量引用了一个新的 Boolean
对象(包装了 true
),而 originalValue.value
仍然引用原来的 Boolean
对象(包装了 false
)。
因此,当我们在 main
方法的最后打印出 originalValue.value
的值时,它仍然是 false
,因为 originalValue.value
引用的 Boolean
对象并没有被改变。
所以,输出结果将会是:
After method call: false
1.5)问题05: Java中引用变量赋值和引用变量修改的区别
public class BooleanWrapper {public Boolean value;public List<Integer> list;public BooleanWrapper(boolean value, List<Integer> list) {this.value = value;this.list = list;}
}public class Test {public static void main(String[] args) {BooleanWrapper originalValue = new BooleanWrapper(false, new ArrayList(Arrays.asList(111)));List<Integer> list = originalValue.list;list.add(222); // 此时,会影响 originalValue.list 为[111,222]list = Arrays.asList(333); // 此时,不会影响 originalValue.list,其还是 为[111,222] ,只是 list为 [333]了System.out.println("After method call: " + originalValue.list); }}