终端开发

使用Android Studio开发可独立运行(runnable)混淆过的Jar程序 Android安装包精简系列之资源精简 Android安装包精简系列之图片优化 Android安装包精简系列之为什么要优化精简安装包 Android安装包精简系列(总纲) Android安装包精简系列之图标转字体 gradle相关资料汇总 Android编译常见错误解决 Android编译编译速度提升 终端基于gradle的开源项目运行环境配置指引 制作终端产品演示的gif 一个关于APK Signature Scheme v2签名的神奇bug定位经历 如何随apk一起打包并使用SQLite SDK热更之gradle插件(如何在SDK代码中自动插桩及如何生成补丁包) 关于Android的APK Signature Scheme v2签名相关的资料汇总 封装HttpURLConnection实现的简单的网络请求库 一款基于Java环境的读取应用包名、签名、是否V2签名等基本信息的工具 Android的APK Signature Scheme v2签名及一款基于Java环境的校验工具介绍 如何使用Eclipse开发可执行Jar程序,并生成混淆过的jar程序 Android 相关的学习资料整理(持续更新) macOS(Sierra 10.12)上Android源码(AOSP)的下载、编译与导入到Android Studio Google也看不下去被玩坏的悬浮窗了么? Android开发常用工具资源 SDK热更系列之概述(持续整理编辑中~) SDK热更系列之SDKHotfix待优化点 Android 终端开发相关的一些神图(持续更新) SDK热更系列之Demo项目介绍概述 SDK热更系列之Demo体验方法 SDK热更系列之如何获取应用在当前设备上的so对应的指令集 Gradle Android插件使用的中那些特别注意的点 Experimental Plugin User Guide(From Android Tools Project Site) 基于Android Studio使用gradle构建包含jni以及so的构建实例 基于Instrumentation框架的自动化测试 - Android自动化测试系列(四) Instrumentation框架介绍-Android自动化测试系列(三) 关于终端设备的设备唯一性的那些事之MAC地址 关于终端设备的设备唯一性的那些事之IMEI Android 检查应用是否有root权限 ant常见错误解决方案 Gradle介绍 iMac上Android Studio 相关设置及常见问题 再说adb 再看Android官方文档之分享 再看Android官方文档之Fragment&数据保存 再看Android官方文档之Activity&Intent 再看Android官方文档之ActionBar和兼容性 adb shell input(Android模拟输入)简单总结 再看Android官方文档之建立第一个APP Android开发调试常用工具 ANR(网络资料整理) Java参数引用传递引发的惨案(又一次Java的String的“非对象”特性的踩坑经历) android.view.WindowManager$BadTokenException,Unable to add window Android签名校验机制(数字证书) Robotium二三事-Android自动化测试系列(二) Robotium介绍-Android自动化测试系列(一) Android开发中遇到的那些坑 Eclipse使用中部分经验总结 Android中关于Nativa编译(NDK、JNI)的一些问题 Android简单实现的多线程下载模块 Android内存耗用之VSS/RSS/PSS/USS adb Advanced Command URL编码中的空格(编码以后变为+) Android MD5后 bye数组转化为Hex字符串的坑(记一次为女神排忧解难的经历) Android学习之路 adb Base Command Android Log的那些坑…………

标签

android 46

Android编译常见错误解决 一个关于APK Signature Scheme v2签名的神奇bug定位经历 关于Android的APK Signature Scheme v2签名相关的资料汇总 封装HttpURLConnection实现的简单的网络请求库 一款基于Java环境的读取应用包名、签名、是否V2签名等基本信息的工具 Android的APK Signature Scheme v2签名及一款基于Java环境的校验工具介绍 如何使用Eclipse开发可执行Jar程序,并生成混淆过的jar程序 Android 相关的学习资料整理(持续更新) macOS(Sierra 10.12)上Android源码(AOSP)的下载、编译与导入到Android Studio Android开发常用命令备忘 Google也看不下去被玩坏的悬浮窗了么? Android开发常用工具资源 Android 终端开发相关的一些神图(持续更新) Gradle Android插件使用的中那些特别注意的点 Experimental Plugin User Guide(From Android Tools Project Site) iMac(OS X)搭建私有maven仓库,提供Nexus Responsitory镜像 基于Android Studio使用gradle构建包含jni以及so的构建实例 基于Instrumentation框架的自动化测试 - Android自动化测试系列(四) Instrumentation框架介绍-Android自动化测试系列(三) 关于终端设备的设备唯一性的那些事之MAC地址 关于终端设备的设备唯一性的那些事之IMEI Android 检查应用是否有root权限 iMac(OS X)El Capitan 更新遇到的那些坑 ant常见错误解决方案 Gradle介绍 iMac上Android Studio 相关设置及常见问题 再说adb 再看Android官方文档之分享 再看Android官方文档之Fragment&数据保存 再看Android官方文档之Activity&Intent 再看Android官方文档之ActionBar和兼容性 adb shell input(Android模拟输入)简单总结 再看Android官方文档之建立第一个APP Android开发调试常用工具 ANR(网络资料整理) Java参数引用传递引发的惨案(又一次Java的String的“非对象”特性的踩坑经历) android.view.WindowManager$BadTokenException,Unable to add window Android签名校验机制(数字证书) Eclipse使用中部分经验总结 Android内存耗用之VSS/RSS/PSS/USS adb Advanced Command URL编码中的空格(编码以后变为+) Android MD5后 bye数组转化为Hex字符串的坑(记一次为女神排忧解难的经历) Android学习之路 adb Base Command Android Log的那些坑…………

Java参数引用传递引发的惨案(又一次Java的String的“非对象”特性的踩坑经历)

2015年05月13日

前几天帮别人写一个SDK的Demo代码,遇到个问题。里面有一个接口,参数为String,要引用传递。然后发现代码执行结束以后,这个String对象的值并没修改。

查了好久才发现又进了一个之前踩过的坑。果然基础知识要定期巩固,就专门对Java的参数传递和String简单汇总整理下。先在上面说了结论,然后再在后面举证。

总结:

传值传递:

参数传入方法时,无论该参数在方法内怎样被改变,外部的变量原型总是不变,叫做“值传递”。即方法操作的是参数变量(也就是原型变量的一个值的拷贝)改变的也只是原型变量的一个拷贝而已,而非变量本身。所以变量原型并不会随之改变。

传址传递:

参数传入方法时,方法改变参数变量的同时变量原型也会随之改变,这种特性就叫做“引用传递”,也叫做传址。即方法操作参数变量时是拷贝了变量的引用,而后通过引用找到变量(在这里是对象)的真正地址,并对其进行操作。

Java的参数传递:

  • Java对于基本类型的参数以值传递的方式,对于非基本类型(对象类型)的参数以引用传递的方式。
  • String虽然是对象类型,但是String是不可变的对象,在每次对String 类型进行改变的时候,都会生成一个新的 String 对象。因此导致当String作为参数传递的时候,感官上是传值传递。具体的说:当String作为参数传递时,确实是以地址传递过去的,但是在对String类型的变量的值进行改变时,由于String类的值是常量,在创建后不能更改,所以对String参数进行操作,相当于new String(),已经改变了String对象的地址了,所以实参不会改变。

  • 如果非要用类似String类型的变量参数引用传递,可以使用StringBuffer或者StringBuilder

String的“非对象”特性:

String是不可变的对象, 因此在每次对String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象

推荐好文:

之前在ImportNew的微信公共号上看到一篇关于Java String、StringBuilder和StringBuffer(点击查看)的文章,感觉还不错,推荐一下,也是备忘。

举证:

Java 基本类型传递:

测试代码1:

public class Test{

	public static void testFunction(int para){
    	para = para + 5;
    	System.out.println("Func para is:"+ para);
	}

	public static void main(String[] args) {
		int a = 5;
		System.out.println("Main para is:"+ a);
		testFunction(a);
		System.out.println("Main para after func is:"+ a);
	}
}

运行结果1:

➜  temp  javac Test.java && java Test
	Main para is:5
	Func para is:10
	Main para after func is:5
➜  temp

测试代码2:

public class Test {

	public static void testFunction(Integer para) {
		para = para + 5;
		System.out.println("Func para is:" + para);
	}

	public static void main(String[] args) {
		Integer a = 5;
		System.out.println("Main para is:" + a);
		testFunction(a);
		System.out.println("Main para after func is:" + a);
	}
}

运行结果2:

➜  temp  javac Test.java && java Test
	Main para is:5
	Func para is:10
	Main para after func is:5
➜  temp

概要分析:

  • 基本类型作为参数时,只是值传递,因此函数执行结果不会影响参数的原值。
  • Integer 作为int的一个封装类在作为参数的时候存在和int一样的特性。以此类推,在Java中Float、Double这些对基本类型进行封装的类同样也是值传递。

Java 对象类型传递:

测试代码:

public class TestObj {

	public String mKey = "";

	public TestObj(String para) {
		this.mKey = para;
	}

	public String toString() {
		return mKey;
	}
}

public class Test {

	public static void testFunction(TestObj para) {
		para.mKey = para.mKey + " world!";
		System.out.println("Func para is:" + para.toString());
	}

	public static void main(String[] args) {
		TestObj a = new TestObj("hello");
		System.out.println("Main para is:" + a.toString());
		testFunction(a);
		System.out.println("Main para after func is:" + a.toString());
	}
}

运行结果:

➜  temp  javac TestObj.java Test.java && java Test
	Main para is:hello
	Func para is:hello world!
	Main para after func is:hello world!
➜  temp

概要分析:

  • 对象类型最为参数的时候是引用传递,因此在函数中对TestObj的mKeyde修改会被永久的修改,一直保存下来。

Java String类型传递:

测试代码:

public class Test{

	public static void testFunction(String para){
    	para = para + " world!";
    	System.out.println("Func para is:"+ para);
	}

	public static void main(String[] args) {
		String a = "hello";
		System.out.println("Main para is:"+ a);
		testFunction(a);
		System.out.println("Main para after func is:"+ a);
	}
}

运行结果:

➜  temp  javac Test.java && java Test
	Main para is:hello
	Func para is:hello world!
	Main para after func is:hello
➜  temp

概要分析:

  • String作为函数参数的时候,最终的表现类似值传递。这是因为String是一个长度不可变的常量。当在函数中对String的值进行修改的时候,其实是重新new了一个对象。而这个对象的地址已经不是main函数中para所指向的位置。函数结束以后,这个String自动销毁,para的值保持不变。

Java StringBuilder类型传递:

测试代码:

public class Test {

	public static void testFunction(StringBuilder para) {
		para = para.append(" world!");
		System.out.println("Func para is:" + para.toString());
	}

	public static void main(String[] args) {
		StringBuilder a = new StringBuilder("hello");
		System.out.println("Main para is:" + a.toString());
		testFunction(a);
		System.out.println("Main para after func is:" + a.toString());
	} }

运行结果:

➜  temp  javac Test.java && java Test
	Main para is:hello
	Func para is:hello world!
	Main para after func is:hello world!
➜  temp

概要分析:

  • StringBuilder作为函数参数的时候,因为是一个对象,所以是引用传递。StringBuffer、StringBuilder 长度都是可变的,因此在做append操作的时候并不是重新new 一个对象,而是直接在原对象继续操作。所以这种修改也被永久的保存了下来。


PS:我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=10zhijuy24v4f

赞赏

取消
微信扫一扫,赞赏子勰
扫码支持
屌丝程序猿,鸡血攻城狮!努力学技术,潜心做精品!