Java 7 中的Switch 谈 Java版本更新和反编译知识
Java 7 中的Switch 谈 Java版本更新和反编译知识
学习编程,享受生活,大家好,我是追寻梦的飞飞。今天主要讲述的是Java7中的更新Switch实现内部原理和JAD反编译知识,反编译很好玩的!
Java语言大版本之间的更新,会添加一些比较好的改动。目前最流行的应该是Java7 版本的,现在java 8 已经推出,更多的是关注与移动互联网领域,比如位置信息、触摸即使、罗盘指针、重力感应之类的。不过到java 8 推广还有一段时间,所以就先学习Java7中的新改动的知识了。软件版本更新需要考虑对之间版本的兼容性,让版本更新的代价最小,这一点在Switch中是如何体现的呢?
之前的Java中Switch仅仅支持整形的数据,所以给编程带来一定的困扰,极大的限制了程序的灵活性(我想说的是C/C++中好像也是仅仅支持类int类型的变量)。但是在Java7中增加了一种String类型,Switch语句支持Character Byte Short Integer String类型。但是这一种方式的改变,在底层如何实现,怎样修改使得代价最小:
在Switch语句中,case中的值是不可以相等的,经过编译之后的Java代码会全部转为Unicode字符:所以下面的情况是不会通过编译的:
String gender = “”;
switch(gender){
case “男”:
break;
case “\u7537”:
break;
}
这样的代码是不会被编译通过的。因为unicode中的\u7537就是汉字男
在底层的实现原理:
因为之前的Switch是仅仅支持int类型的,也就是说在JVM和字节码层次上仅仅支持int类型的变量,那么减少这个改变带来的影响,就需要根据源代码中的含义,将字符串转变为对应的int值,不同的JAVA编译器采用不同的方式进行转变,这里我们想到的就是Java的hashCode。
这里就需要介绍一个很好的工具JAD,它可以反编译,也就是把字节码编译成为Java源代码,好像很厉害的样子,于是我就忍不住,赶紧来试一下,如果可以反编译别人的字节码,那岂不是碉堡了,在反编译之前,我们先大胆的猜一下:Java的反编译应该是比C/C++的要简单的多,因为JVM 的标准是开放的,所以生成的字节码也是有规律的,但是反编译之后的源代码应该和自己写的源代码有一定的差别,但是差别会有多大,感觉不会很大。因为每一个JAVA文件是独自的编译的,生成对应的字节码。我们测试一下:
首先是下载工具和配置环境了:很小的几百k,加压出来发现就两个文件执行exe和说明文档。为了能够在命令行中可以运行,我们直接把她放在JDK/bin中,前提是你配置了JAVA环境变量。
开始测试了:
1.输入jad命令,可以运行
2.找个自己的源代码
TestMain.java
import java.io.InputStream;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.yang.lolvideo.jetty.handler.LolHandler;
public class TestMain {
private static final int PORT_ONE = 8087;
private static final int PORT_TWO = 8088;
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
//Spring config
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//ehcache config to get the object cache
InputStream ehcacheConfig = TestMain.class.getResourceAsStream("ehcache.xml");
CacheManager cacheManager = CacheManager.create(ehcacheConfig);
Cache cache = cacheManager.getCache("sampleCache1");
//Jetty server to run the server
Server server =new Server();
ServerConnector connector_one = new ServerConnector(server);
connector_one.setPort(PORT_ONE);
ServerConnector connector_two = new ServerConnector(server);
connector_two.setPort(PORT_TWO);
server.setConnectors(new Connector[]{connector_two});
Handler handler = new LolHandler(context,cache);
server.setHandler(handler);
//start server
server.start();
server.join();
}
}
将他的字节码反编译
jad –p TestMain.class > TestMain.java // 将编译的结果重定向到文件
jad –p TestMain.class // 将编译的结果显示在屏幕
jad –o TestMain.class > TestMain.java // 不提示,直接覆盖原文件
查看源文件:
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: TestMain.java
import com.yang.lolvideo.jetty.handler.LolHandler;
import net.sf.ehcache.CacheManager;
import org.eclipse.jetty.server.*;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestMain
{
public TestMain()
{
}
public static void main(String args[])
throws Exception
{
org.springframework.context.ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
java.io.InputStream ehcacheConfig = TestMain.getResourceAsStream("ehcache.xml");
CacheManager cacheManager = CacheManager.create(ehcacheConfig);
net.sf.ehcache.Cache cache = cacheManager.getCache("sampleCache1");
Server server = new Server();
ServerConnector connector_one = new ServerConnector(server);
connector_one.setPort(8087);
ServerConnector connector_two = new ServerConnector(server);
connector_two.setPort(8088);
server.setConnectors(new Connector[] {
connector_two
});
org.eclipse.jetty.server.Handler handler = new LolHandler(context, cache);
server.setHandler(handler);
server.start();
server.join();
}
private static final int PORT_ONE = 8087;
private static final int PORT_TWO = 8088;
}
果然是超厉害,这反编译的写的代码比我自己的源代码更加规范,我和我的小伙伴们的哦惊呆了,这样岂不是可以……你懂的
还是回来说说这些switch实现的机制:
源代码是:
//TestMain.java
public class TestMain
{
public String generatee(String name, String gender){
String title="";
switch(gender){
case "男":
title= name + "先生";
break;
case "女":
title=name+ "女士";
break;
default:
title = name;
}
return title;
}
}
反编译之后:
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: TestMain.java
public class TestMain
{
public TestMain()
{
}
public String generatee(String s, String s1)
{
String s2 = "";
String s3 = s1;
byte byte0 = -1;
switch(s3.hashCode())
{
case 30007:
if(s3.equals("\u7537"))
byte0 = 0;
break;
case 22899:
if(s3.equals("\u5973"))
byte0 = 1;
break;
}
switch(byte0)
{
case 0: // '\0'
s2 = (new StringBuilder()).append(s).append("\u5148\u751F").toString();
break;
case 1: // '\001'
s2 = (new StringBuilder()).append(s).append("\u5973\u58EB").toString();
break;
default:
s2 = s;
break;
}
return s2;
}
}
在底层原来是这样实现的,在转变为hashCode之后,也会在内部使用equal函数进行判断。因为不同的对象产生的hashCode也会有相等的时候。在这里吧他们转变为byte的0,1,2,之后在来一个switch进行判断,执行对应的操作。
所以说在在底层执行代码不一定就是我们编写的代码,这个时候我们就应给考虑执行效率的问题。如果对于这种switch我们可以尝试使用enum类型来进行优化。
今天就先到这里了,不断的学习新的技术,和大家分享!
追寻梦的飞飞
2014.04.02 于广州
Java 7 中的Switch 谈 Java版本更新和反编译知识的更多相关文章
- Java 14中对switch的增强,终于可以不写break了
面对这样的if语句,你是不是很难受呢? if (flag == 1) { log.info("didispace.com: 1"); } else if (flag == 2) { ...
- .NET中使用switch和java不一样的地方。
1.不能这样贯穿 我们知道,java 和 C在使用switch时候可以这样. switch (i) { //java中此处不使用break // 执行了case 1:对应的语句后直接 贯穿到 case ...
- Java 17中对switch的模式匹配增强
还记得Java 16中的instanceof增强 吗? 通过下面这个例子再回忆一下: Map<String, Object> data = new HashMap<>(); d ...
- java switch case 枚举类型的反编译结果
package com.example.demo; import java.io.PrintStream; // Referenced classes of package com.example ...
- 对Java代码加密的两种方式,防止反编译
使用Virbox Protector对Java项目加密有两种方式,一种是对War包加密,一种是对Jar包加密.Virbox Protector支持这两种文件格式加密,可以加密用于解析class文件的j ...
- 浅谈java中异常抛出后代码是否会继续执行
问题 今天遇到一个问题,在下面的代码中,当抛出运行时异常后,后面的代码还会执行吗,是否需要在异常后面加上return语句呢? public void add(int index, E element) ...
- HAL中通过JNI调用java方法【转】
转载请注明本文出处:http://www.cnblogs.com/xl19862005 作者:Xandy 由于工作的需要,最近一直在研究HAL.JNI.Java方法之间互调的问题,并做了如下一些记录和 ...
- Intellij Idea 工具在java文件中如何避免 import .*包
Intellij Idea工具在java文件中怎么避免import java.utils.*这样的导入方式,不推崇导入*这样的做法!Editor->Code Style->Java-> ...
- 关于Java运算中类型自动提升的问题
1.表达式中的自动类型提升: 表达式求值时,Java自动的隐含的将每个byte.short或char操作数提升为int类型,这些类型的包装类型也是可以的. 例如:short s1 = 1; s1 = ...
随机推荐
- mingw编译rtmp库
下载rtmpdump-2.4 进到里面的librtmp目录下面,执行命令:make SYS=mingw CRYPTO= 这样就编译成功静态库和动态库,如何安装到/usr/local/下面? 执行命令: ...
- 基于AutoCAD的ObjectARX之NET扩展(mcnetarx)-AcdbEntNext、AcdbEntLast
1.AcdbEntLast用于获取最后一个创建的实体. 2.AcdbEntNext用于获取指定实体名称之后的下一个创建的实体. ' 定义保存实体名称的变量 Dim ent() As Integer = ...
- .NET相关操作其他文件的小程序(系列文章)
平时自诩为使用.NET做开发,但是实际上从一开始学习C#直到现在除了做个几个不登大雅之堂的小网站,做过几个winform程序和几个控制台应用程序,真的没有踏踏实实地用.NET开发过某些属于自己的东西. ...
- 关于普通定时器与高级定时器的 PWM输出的初始化的区别
不管是普通定时器还是高级定时器,你用哪个通道,就在程序里用OC多少.比如CH3对应OC3 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_ ...
- SHELL实现同时操作多个服务器:服务器批量管理
引言: 1.如果你想知道你所管理的几万台服务器的/home分区使用率是多少. 2.如果你想为你所管理的几万台服务器添加同一个计划任务你该怎么办? 3.如果你想让你所管理的几万台 ...
- Webdriver实现原理
通过研究selenium-webdriver的源码,笔者发现其实webdriver的实现原理并不高深莫测无法揣度.在这里以webdriver ruby binding的firefox-webdrive ...
- Perst常用命令
Perst我使用的版本是4, 几乎支持所有的.net环境, 而且效率很高,比较稳定. 使用方法: 1:引用相应dll 2: 创建数据结构 public class Cp_struct : Persis ...
- Win10 无法完全关机问题
Win10是重新安装的.开机运行时间长了或者跑的东西多了.关机,键盘灯还是亮的,要强制按电源键关机才行. 问题解决:从网上搜以为是显卡驱动问题,上官网更新最新驱动,结果还是关不了机.偶然间搜到是Int ...
- PAT/进制转换习题集
B1022. D进制的A+B (20) Description: 输入两个非负10进制整数A和B(<=230-1),输出A+B的D (1 < D <= 10)进制数. Input: ...
- Ubuntu 初始化Root账户密码
昨晚新装的Ubuntu12(电脑太烂了),每次都记不住初始化root密码的命令,既然决定开始写自己的园子了,那就在自己的园子里面记一下,方便自己稳固之心 好了,不废话了了 draenei@ubuntu ...