匿名对象的值传递
目录
线程池目录
前言
在学习线程池的时候,发现采用创建匿名对象的时候,匿名对象内外的传递并非形参通用传递。这不经让我回忆起在校期间用SWING编写的一个socket音乐播放器在监听器里面也遇到过同样的问题:JList实现随意切换歌曲、更新线程以及问题分析,时间久远了,应该是采用全局变量解决的,当初以为是十天的课设,时间仓促,未来得及深究。这次来分析一下。
一般调用
final调用
一般调用采用定义final变量,大家都知道final关键字是设置值不可变(基本类型)和引用不可变(对象)的变量;
for (int i = 0; i < 10; i++) {
final int index = i;
cachedThreadPool.execute(new Runnable() {
public void run() {
System.out.println(index);
}
});
}
是否需要final
那么如果在for循环里面将final去掉呢?是的没有报错,那么是不是跟不需要采用final了呢?
明显不是的,当我们进行对index在作用范围(for循环中)进行值处理的时候:
Local variable index defined in an enclosing scope must be final or effectively final
这是什么意思?
报错信息:在封闭范围内定义的局部变量索引必须是最终的或有效的。 【当然这是报错的表面现象】
实际上当你使用int index的时候,不在匿名对象里面改变该值,那么他本质上是一个final。但是如果你尝试改变,便触犯了表述一致性的原则。为什么这么说呢,我们先看一下匿名内部对象的实际编译等效代码。
匿名内部类的实际代码
这里引用他人的例子作为举例(链接见参考文档) :
这简单的说匿名内部对象里面传入使用的参数表面看是直接引用局部变量,实际上是值传递进去的。知道这一点便好理解了。
//定义个抽象类
abstract class AbstractClass{
public abstract void m();
}
public static void test(final String s){
AbstractClass c = new AbstractClass(){
public void m(){
s = "inner";
System.out.println(s);
}
};
}
实际编译结果:
public static void test(final String s){
class OuterClass$1 extends AbstractClass{
private final String s;
public OuterClass$1(String s){
this.s = s;
}
public void m(){
s = "inner";
System.out.println(s);
}
};
AbstractClassc = new OuterClass$1(s);
}
如何理解
Java的值传递
当我们往一个参数里面传值的时候,相当于C里面的值传递(JAVA是C写的)。当我们传对象/数组的时候是引用传递。而值传递实质上是copy(复制)值的引用指针
以上面的代码index为例,当不改变任何一个index的时候(实质为final)
自定义类引用传递举例
可以看到,add方法并未返回任何数据,但是主函数的testObj对象还是值得到了改变。
public static void main(String[] args) {
int n =0;
TestObj testObj = new TestObj(n);
add(testObj);
System.out.println("这是形参对象的n的自增2的结果:" + testObj.val);
System.out.println("这是main函数里面的n:" + n);
}
public static void add(TestObj temp) {
temp.val+=2;
}
Console:
这是形参对象的n的自增2的结果:2
这是main函数里面的n:0
值传递导致的表述一致性问题
再回到原来的int和final int问题。
当main函数中的index改变后,两个index的值指向。问问自己,这个时候的main函数中和形参中的值index还是同一个值吗?
明显不是。
如何传递匿名内部类参数
- 引用传递:数组、类对象等;
- 全局变量;
- 不修改的final变量。
参考文档
????都看到文末了,好文要顶,一键三连????~
本文地址:https://blog.csdn.net/qq_37334150/article/details/109530616