JSR303
JSR303是一套JavaBean参数校验的标准,定义了很多常用的校验注解。我们需要对前端传的参数进行校验。 ...
JSR303是一套JavaBean参数校验的标准,定义了很多常用的校验注解。我们需要对前端传的参数进行校验。 ...
SPI ,全称为 Service Provider Interface,是一种服务发现机制。它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类。 这一机制为很多框架扩展提供了可能,比如在Dubbo、JDBC中都使用到了SPI机制。我们先通过一个很简单的例子来看下它是怎么用的。 ...
java反编译 在介绍编译和反编译之前,我们先来简单介绍下编程语言(Programming Language)。编程语言(Programming Language)分为低级语言(Low-level Language)和高级语言(High-level Language)。 机器语言(Machine Language)和汇编语言(Assembly Language)属于低级语言,直接用计算机指令编写程序。 而C、C++、Java、Python等属于高级语言,用语句(Statement)编写程序,语句是计算机指令的抽象表示。 举个例子,同样一个语句用C语言、汇编语言和机器语言分别表示如下: 编程语言 表示形式 C语言 a=b+1; 汇编 mov 0x804a01c,%eax add $Ox1,%eax mov %eax,0x804a018 机器语言 a1 1c a0 04 0883 c0 01a3 18 a0 04 08 计算机只能对数字做运算,符号、声音、图像在计算机内部都要用数字表示,指令也不例外,上表中的机器语言完全由十六进制数字组成。最早的程序员都是直接用机器语言编程,但是很麻烦,需要查大量的表格来确定每个数字表示什么意思,编写出来的程序很不直观,而且容易出错,于是有了汇编语言,把机器语言中一组一组的数字用助记符(Mnemonic)表示,直接用这些助记符写出汇编程序,然后让汇编器(Assembler)去查表把助记符替换成数字,也就把汇编语言翻译成了机器语言。但是,汇编语言用起来同样比较复杂,后面,就衍生出了Java、C、C++等高级语言。 什么是编译? 上面提到语言有两种,一种低级语言,一种高级语言。可以这样简单的理解:低级语言是计算机认识的语言、高级语言是程序员认识的语言。那么如何从高级语言转换成低级语言呢?这个过程其实就是编译。 从上面的例子还可以看出,C语言的语句和低级语言的指令之间不是简单的一一对应关系,一条a=b+1;语句要翻译成三条汇编或机器指令,这个过程称为编译(Compile),由编译器(Compiler)来完成,显然编译器的功能比汇编器要复杂得多。用C语言编写的程序必须经过编译转成机器指令才能被计算机执行,编译需要花一些时间,这是用高级语言编程的一个缺点,然而更多的是优点。首先,用C语言编程更容易,写出来的代码更紧凑,可读性更强,出了错也更容易改正。 将便于人编写、阅读、维护的高级计算机语言所写作的源代码程序,翻译为计算机能解读、运行的低阶机器语言的程序的过程就是编译。负责这一过程的处理的工具叫做编译器。 现在我们知道了什么是编译,也知道了什么是编译器。不同的语言都有自己的编译器,Java语言中负责编译的编译器是一个命令:javac javac是收录于JDK中的Java语言编译器。该工具可以将后缀名为.java的源文件编译为后缀名为.class的可以运行于Java虚拟机的字节码。 当我们写完一个HelloWorld.java文件后,我们可以使用javac HelloWorld.java命令来生成HelloWorld.class文件,这个class类型的文件是JVM可以识别的文件。通常我们认为这个过程叫做Java语言的编译。其实,class文件仍然不是机器能够识别的语言,因为机器只能识别机器语言,还需要JVM再将这种class文件类型字节码转换成机器可以识别的机器语言。 什么是反编译? 反编译的过程与编译刚好相反,就是将已编译好的编程语言还原到未编译的状态,也就是找出程序语言的源代码。就是将机器看得懂的语言转换成程序员可以看得懂的语言。Java语言中的反编译一般指将class文件转换成java文件。 有了反编译工具,我们可以做很多事情,最主要的功能就是有了反编译工具,我们就能读得懂Java编译器生成的字节码。 如何防止反编译? 由于我们有工具可以对Class文件进行反编译,所以,对开发人员来说,如何保护Java程序就变成了一个非常重要的挑战。但是,魔高一尺、道高一丈。当然有对应的技术可以应对反编译咯。但是,这里还是要说明一点,和网络安全的防护一样,无论做出多少努力,其实都只是提高攻击者的成本而已。无法彻底防治。 典型的应对策略有以下几种: 隔离Java程序 让用户接触不到你的Class文件 对Class文件进行加密 提到破解难度 代码混淆 将代码转换成功能上等价,但是难于阅读和理解的形式 Java反编译工具 Javap javap是jdk自带的一个工具,可以对代码反编译,也可以查看java编译器生成的字节码。javap和其他两个反编译工具最大的区别是他生成的文件并不是java文件,也不像其他两个工具生成代码那样更容易理解。拿一段简单的代码举例,如我们想分析Java 7中的switch是如何支持String的,我们先有以下可以编译通过的源代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class switchDemoString { public static void main(String[] args) { String str = "world"; switch (str) { case "hello": System.out.println("hello"); break; case "world": System.out.println("world"); break; default: break; } } } 执行以下两个命令: 1 2 javac switchDemoString.java javap -c switchDemoString.class 生成代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public class com.hollis.suguar.switchDemoString { public com.hollis.suguar.switchDemoString(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: ldc #2 // String world 2: astore_1 3: aload_1 4: astore_2 5: iconst_m1 6: istore_3 7: aload_2 8: invokevirtual #3 // Method java/lang/String.hashCode:()I 11: lookupswitch { // 2 99162322: 36 113318802: 50 default: 61 } 36: aload_2 37: ldc #4 // String hello 39: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z 42: ifeq 61 45: iconst_0 46: istore_3 47: goto 61 50: aload_2 51: ldc #2 // String world 53: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z 56: ifeq 61 59: iconst_1 60: istore_3 61: iload_3 62: lookupswitch { // 2 0: 88 1: 99 default: 110 } 88: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream; 91: ldc #4 // String hello 93: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 96: goto 110 99: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream; 102: ldc #2 // String world 104: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 107: goto 110 110: return } 我个人的理解,javap并没有将字节码反编译成java文件,而是生成了一种我们可以看得懂字节码。其实javap生成的文件仍然是字节码,只是程序员可以稍微看得懂一些。如果你对字节码有所掌握,还是可以看得懂以上的代码的。其实就是把String转成hashcode,然后进行比较。 个人认为,一般情况下我们会用到javap命令的时候不多,一般只有在真的需要看字节码的时候才会用到。但是字节码中间暴露的东西是最全的,你肯定有机会用到,比如我在分析synchronized的原理的时候就有是用到javap。通过javap生成的字节码,我发现synchronized底层依赖了ACC_SYNCHRONIZED标记和monitorenter、monitorexit两个指令来实现同步。 jad jad是一个比较不错的反编译工具,只要下载一个执行工具,就可以实现对class文件的反编译了。还是上面的源代码,使用jad反编译后内容如下: 命令:jad switchDemoString.class 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class switchDemoString { public switchDemoString() { } public static void main(String args[]) { String str = "world"; String s; switch((s = str).hashCode()) { default: break; case 99162322: if(s.equals("hello")) System.out.println("hello"); break; case 113318802: if(s.equals("world")) System.out.println("world"); break; } } } 看,这个代码你肯定看的懂,因为这不就是标准的java的源代码么。这个就很清楚的可以看到原来字符串的switch是通过****equals()和hashCode()方法来实现的。 但是,jad已经很久不更新了,在对Java7生成的字节码进行反编译时,偶尔会出现不支持的问题,在对Java 8的lambda表达式反编译时就彻底失败。 crf jad很好用,但是无奈的是很久没更新了,所以只能用一款新的工具替代他,CFR是一个不错的选择,相比jad来说,他的语法可能会稍微复杂一些,但是好在能用。我们使用cfr对刚刚的代码进行反编译。执行以下命令: 1 java -jar cfr_0_125.jar switchDemoString.class --decodestringswitch false 得到以下代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class switchDemoString { public static void main(String[] arrstring) { String string; String string2 = string = "world"; int n = -1; switch (string2.hashCode()) { case 99162322: { if (!string2.equals("hello")) break; n = 0; break; } case 113318802: { if (!string2.equals("world")) break; n = 1; } } switch (n) { case 0: { System.out.println("hello"); break; } case 1: { System.out.println("world"); break; } } } } 通过这段代码也能得到字符串的switch是通过equals()和hashCode()方法来实现的结论。 相比Jad来说,CFR有很多参数,还是刚刚的代码,如果我们使用以下命令,java -jar cfr_0_125.jar switchDemoString.class,输出结果就会不同: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class switchDemoString { public static void main(String[] arrstring) { String string; switch (string = "world") { case "hello": { System.out.println("hello"); break; } case "world": { System.out.println("world"); break; } } } } 所以--decodestringswitch表示对于switch支持string的细节进行解码。类似的还有--decodeenumswitch、--decodefinally、--decodelambdas等。在我的关于语法糖的文章中,我使用--decodelambdas对lambda表达式警进行了反编译。 源码: 1 2 3 4 public static void main(String... args) { List<String> strList = ImmutableList.of("Hollis", "公众号:Hollis", "博客:www.hollischuang.com"); strList.forEach( s -> { System.out.println(s); } ); } java -jar cfr_0_125.jar lambdaDemo.class --decodelambdas false反编译后代码: 1 2 3 4 5 6 7 8 public static /* varargs */ void main(String ... args) { ImmutableList strList = ImmutableList.of((Object)"Hollis", (Object)"\u516c\u4f17\u53f7\uff1aHollis", (Object)"\u535a\u5ba2\uff1awww.hollischuang.com"); strList.forEach((Consumer<String>)LambdaMetafactory.metafactory(null, null, null, (Ljava/lang/Object;)V, lambda$main$0(java.lang.String ), (Ljava/lang/String;)V)()); } private static /* synthetic */ void lambda$main$0(String s) { System.out.println(s); } CFR还有很多其他参数,均用于不同场景,读者可以使用java -jar cfr_0_125.jar --help进行了解。这里不逐一介绍了。 Java实例变量和类变量 Java程序的变量大体可分为成员变量和局部变量。其中局部变量可分为如下3类。 形参:在方法签名中定义的局部变量,由方法调用者负责为其赋值,随方法的结束而消亡。 方法内的局部变量:在方法内定义的局部变量,必须在方法内对其进行显示初始化。这种类型的局部变量从初始化完成后开始生效,随方法的结束而消亡。 代码块的局部变量:在代码块内定义的局部变量,必须在代码块内对其进行显式初始化,这种类型的局部变量从初始化完成后开始生效,随代码的结束而消亡。 ...
jvm全面思维导图 java内存模型 什么是虚拟机 windows只能安装exe安装包,mac只能安装dmg安装包,这是因为操作系统底层的实现是不一样的。系统软件无法通用是一个常见的问题。 但使用过 Java 的同学都知道,Java 代码可以在Linux 系统运行,也可以在 Windows 系统运行,但我们并没有生成多份不同的代码。所以 Java 语言是如何做到的呢? Java 语言并不直接将代码编译成与系统有关的机器码,而是编译成一种特定的语言规范,这种语言规范我们称之为字节码。无论 Java 程序要在 Windows 系统,还是 Mac 系统,抑或是 Linux 系统,它首先都得编译成字节码文件,之后才能运行。 但即使编译成字节码文件了,各个系统还是无法明白字节码文件的内容,这时候就需要 Java 虚拟机的帮助了。Java 虚拟机会解析字节码文件的内容,并将其翻译为各操作系统能理解的机器码。 java源码->字节码(byte code)->java Virture Machine ->windows\linux code ...
OAuth OAuth 2.0 是目前最流行的授权机制,用来授权第三方应用,获取用户数据。这个标准比较抽象,使用了很多术语,初学者不容易理解。其实说起来并不复杂,下面我就通过一个简单的类比,帮助大家轻松理解,OAuth 2.0 到底是什么。 ...
chapter_02 创建和销毁对象 Creating and Destroying Objects 本章涉及创建和销毁对象:何时以及如何创建对象,何时以及如何避免创建对象,如何确保它们被及时销毁,以及如何管理在销毁之前必须执行的清理操作。 ...
第一个Netty应用程序 Netty 客户端/服务器概览 Echo 客户端和服务器之间的交互是非常简单的;在客户端建立一个连接之后,它会向服务器发送一个或多个消息...
空指针异常 使用 JSR-305/jetbrain 等注解 NotNull Nullable 1 2 3 4 @Nullable public static String getString(){ return null; } 通过在方法参数、返回值、字段等位置显式标记值是否可能为 Null,配合代码检查工具,能够在编...
养成良好的编程习惯。 ...
ffmpeg使用 ffmpeg了解 ffmpeg官网 在使用Java调用FFmpeg处理音视频之前,需要先安装FFmpeg,安装方法分为两种: ...
StringBuilder 简介 StringBuilder 是一个可变的字符序列。它继承于AbstractStringBuilder,实现了CharSequence接口。 StringBuffer 也是继承于AbstractStringBuilder的子类。StringBuffer是线程安全的,StringBuilder是非线程安全的。 ...
String简介 String 是java中的字符串,它继承于CharSequence。 String类所包含的API接口非常多。为了便于今后的使用,我对String的API进行了分类,并都给出的演示程序。 String 和 CharSequence 关系: String 继承于CharSequence,也就是说String也是CharSequence类型。 CharSequence是一个接口,它只包括length(), charAt(int index), subSequence(int start, int end)这几个API接口。除了String实现了CharSequence之外,StringBuffer和StringBuilder也实现了CharSequence接口。 需要说明的是,CharSequence就是字符序列,String、StringBuilder和StringBuffer本质上都是通过字符数组实现的。 StringBuilder 和 StringBuffer 的区别: StringBuilder 和 StringBuffer都是可变的字符序列。它们都继承于AbstractStringBuilder,实现了CharSequence接口。 但是,StringBuilder是非线程安全的,而StringBuffer是线程安全的。 它们之间的关系图如下: ...
简介 简单来说“Shell 编程就是对一堆 Linux 命令的逻辑化处理”。W3Cschool 上的一篇文章是这样介绍 Shell 的,如下图所示。 Shell 编程的 Hello World 学习任何一...
使用Java 11+的HttpClient (推荐) Java 11引入了新的HttpClient API,位于java.net.http包中: 1 2 3 4 5 6...
equals() 的作用 equals() 的作用是用来判断两个对象是否相等。 equals() 定义在JDK的Object.java中。通过判断两个对象的地址是否相等(即,是否是同一个对象)来区分它们是否相等。源码如下: 1 2 3 public boolean equals(Object obj) { return (this == obj); } 既然Object.java中定义了equals()方法,这就意味着所有的Java类都实现了equals()方法,所有的类都可以通过equals()去比较两个对象是否相等。 但是,我们已经说过,使用默认的equals()方法,等价于==方法。因此,我们通常会重写equals()方法:若两个对象的内容相等,则equals()方法返回true;否则,返回fasle。 下面根据类是否覆盖equals()方法,将它分为2类。 若某个类没有覆盖equals()方法,当它的通过equals()比较两个对象时,实际上是比较两个对象是不是同一个对象。这时,等价于通过==去比较这两个对象。 我们可以覆盖类的equals()方法,来让equals()通过其它方式比较两个对象是否相等。通常的做法是:若两个对象的内容相等,则equals()方法返回true;否则,返回fasle。 下面,举例对上面的2种情况进行说明。 ...
Comparable简介 Comparable 是排序接口,若一个类实现了Comparable接口,就意味着该类支持排序。 如果 List 中的类实现了Comparable接口,则该List 可以通过Collections.sort排序。 此外,一个类如果实现了Comparable接口,可以用作TreeMap的键,或TreeSet中的元素,而不需要指定比较器。 ...
web应用服务器 目前较为主流的Web应用服务器 Tomcat —— Apache软件基金会 Jboss ——- JBOSS公司 Weblogic —— BEA公司 Websphere —– IBM公司 IIS —— 微软 支持ASP语言 Web应用服务器的主要作用是让用户可以通过浏览器(HTTP/HTTPS)方式访问你的项目。 ...
Javadoc用于描述类或者方法的作用。Javadoc可以写在类上面和方法上面。官方文档 ...
概述 门面接口: 1 2 3 4 5 6 commons-logging: apache最早提供的日志门面接口,用户可以根据自己喜欢选择不同日志实现框架,而不...
web api 设计。 ...