一个类没有写构造方法时,会有一个默认的无参构造方法,这是编译器帮我们加上的
public class Main{
public static void main(String[] args) {
}
}
这个特性是jdk5开始加入的,对每个基本数据类型所对应的包装类的转换提供便利,编译器会自动生成调用valueOf方法的代码来进行转换
public class Main{
public static void main(String[] args) {
Integer i = 1;
int i2 = i;
}
}
Java泛型是1.5引入的新特性,可以通过泛型来表示任意的类型,提高代码的复用性;但是泛型是不会保留到运行期的,在编译期,编译器就会对泛型进行擦除;实际的操作都会当作Object对象来进行操作
public class Main{
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
//实际上是调用的void add(Object obj)
list.add(1);
//实际上是调用的Object get(int index)
int i = list.get(0);
//相当于编译器帮我们做了(Object)1和(Integer)list.get(0)的强制类型转换的步骤
}
}
泛型信息虽然被擦除了,不会出现在字节码中,但是反编译后出现了一个LocalVariableTypeTable可以看到泛型,通过反射可以得到方法的参数和返回值的泛型信息
public class Main{
public static void main(String[] args) throws NoSuchMethodException {
Method method = Main.class.getMethod("test", List.class, Map.class);
// 得到方法的参数类型,即List和Map
Type[] types = method.getGenericParameterTypes();
for (Type type:types){
// 转化为参数类型对象
ParameterizedType parameterizedType = (ParameterizedType) type;
System.out.println("原始类型:"+parameterizedType.getRawType());
// 得到泛型类型
Type[] arguments = parameterizedType.getActualTypeArguments();
for (int i = 0; i < arguments.length; i++) {
System.out.printf("泛型参数[%d] - %s\n",i,arguments[i]);
}
}
}
public Set<Integer> test(List<String> list, Map<Integer,Object> map){
return null;
}
}
可变参数也是jdk5开始加入的新特性,可变参数实际上在编译期会被转换成一个数组
public class Main{
public static void main(String[] args){
test("123","456");
}
private static void test(String ...args){
}
}
jdk5引入,遍历数组、集合时,可以通过foreach的方式
public class Main{
public static void main(String[] args){
// 直接赋值数组的方式也是一种语法糖,会转换为new int[]{1,2,3}的形式
int[] nums = {1,2,3};
for (int num : nums) {
System.out.println(num);
}
// 上面这种方式会被转换为
for(int i=0;i<nums.length;i++{
int nums = nums[i];
System.out.println(num);
}
}
}
public class Main{
public static void main(String[] args){
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
for (Integer i : list) {
System.out.println(i);
}
// 会被转换成这样
Iterator<Integer> it = list.iterator();
while(it.hasNext()){
Integer i = it.next();
System.out.println(i);
}
}
}
从jdk7开始,switch可以用作字符串和枚举类(原生的switch并不支持),这个功能也是语法糖
public class Main{
public static void main(String[] args){
test("hello");
}
private static void test(String str){
switch (str){
case "hello":
System.out.println("1");
break;
case "bye":
System.out.println("2");
}
// 会变成被转换成下面的形式
byte x = -1;
switch(str.hashCode()){
// "hello"的hashCode
case 99162322:
if("hello".equals(str)){
x=0;
}
break;
// "bye"的hashCode
case 98030:
if("bye".equals(str)){
x = 1;
}
}
switch(x){
case 0:
System.out.println("1");
break;
case 1:
System.out.println("2");
break;
}
}
}
public class Main{
public static void main(String[] args){
System.out.println(Sex.values().length);
}
private static void test(Sex sex){
switch (sex){
case MALE:
System.out.println("male");
break;
case FEMALE:
System.out.println("female");
break;
}
}
// 上面会被转换成下面这样
static class $MAP{
static int[] map = new int[2];
static{
map[Sex.MALE.ordinal()] = 1;
map[Sex.FEMALE.ordinal()] = 2;
}
}
private static void test(Sex sex){
int x = $MAP.map[sex.ordinal()];
switch (x){
case 1:
System.out.println("male");
break;
case 2:
System.out.println("female");
break;
}
}
}
enum Sex{
MALE,FEMALE
}
枚举实际上也是一个class
原代码
enum Sex{
MALE,FEMALE
}
编译期处理后
pulbic final class Sex extends Enum<Sex> {
public static final Sex MALE;
public static final Sex FEMALE;
public static final Sex[] $VALUES;
static {
MALE = new Sex("MALE",0);
FEMALE = new Sex("FEMALE",1);
$VALUES = new Sex[]{MALE,FEMALE};
}
private Sex(String name,int ordinal){
super(name,ordinal);
}
public static Sex[] values(){
return$VALUES.clone();
}
public static Sex valueOf(String name){
return Enum.valueOf(Sex.class,name);
}
}
jdk开始,新增了堆需要关闭的资源处理的特殊语法,即try-with-resources;要求其中资源对象需要实现AutoCloseable接口,例如InputStream、OutputStream、Connection、Statement、ResultSet等接口都实现了AutoCloseable,使用try-with-resources就可以不用写finally语句块,编译器会自动生成关闭资源的代码
原代码
try(InputStream is = new FileInputStream("d:\\1.txt")) {
}catch(IOExeption e){
e.printStackTrace();
}
编译期处理后代码
try{
InputStrem is = new FileInputStream("d:\\1.txt");
Throwable t = null;
try{
}catch(Throwable e1){
t = e1;
throw e1;
}finally {
// 判断资源是否为空
if(is!=null) {
// 如果代码有异常
if(t!=null){
try{
is.close();
}catch (Throwable e2){
// 如果close出现异常,作为被压制异常添加
t.addSuppressed(e2);
}
}else{
// 如果代码没有异常,close出现了异常就是catch中的e,所以不需要再catch
is.close();
}
}
}
}
addSuppressed的方法设计是为了防止异常丢失,在异常跟踪栈中可以看到所有的异常
方法重写的返回值分两种情况:
class A{
public Number m(){
return 1;
}
}
class B extends A{
@Override
public Integer m(){
return 2;
}
}
经过编译期处理后
class B extends A{
public Integer m(){
return 2;
}
// 这个方法才是重写父类方法的,这是一个桥接方法,synthetic bridge关键字只有虚拟机内部使用,对开发者不可见
public synthetic bridge Number m(){
return m();
}
}
源代码
public class Main{
public static void main(String[] args){
Runnable runnable = new Runnable(){
@Override
public void run(){
}
}
}
}
经过编译期转换后
final class Main$1 implements Runnable{
Main$1(){}
public void run(){
}
}
public class Main{
public static void main(String[] args){
Runnable runnable = new Main$1();
}
}