What is synthetic construct?
As per the Java specification, a construct emitted by a Java compiler must be marked as synthetic if it does not correspond to a construct declared explicitly or implicitly in source code, unless the emitted construct is a class initialization method.
In Java, fields, methods and constructors can be synthetic.
Synthetic fields
Let me explain with an example.
public class SyntheticFieldDemo {
public class InnerClass {
}
}
When the above class gets compiled, inner class will contain a synthetic field which references the outer class ‘SyntheticFieldDemo’. This synthetic field is required to access the enclosing class members from a nested class. Let’s see it with an example.
SyntheticFieldDemo.java
public class SyntheticFieldDemo {
public class InnerClass {
}
}
Let’s compile above class.
$javac SyntheticFieldDemo.java
$
$ls *class
SyntheticFieldDemo$InnerClass.class SyntheticFieldDemo.class
As you see above snippet, there are two .class files generated by the compiler. Let’s decompile the class ‘SyntheticFieldDemo$InnerClass.class’ and confirm it has a field reference to the outer class.
$javap SyntheticFieldDemo\$InnerClass.class
Compiled from "SyntheticFieldDemo.java"
public class SyntheticFieldDemo$InnerClass {
final SyntheticFieldDemo this$0;
public SyntheticFieldDemo$InnerClass(SyntheticFieldDemo);
}
How to get the synthetic field information programtically?
Field class provides 'isSynthetic' method, it returns true if this field is a synthetic field, else false.
SyntheticFieldDemo.java
package com.sample.app;
import java.lang.reflect.Field;
public class SyntheticFieldDemo {
public class InnerClass {
}
private static <T> void printFileds(Class<T> clazz) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println("Field: " + field.getName() + ", isSynthetic: " + field.isSynthetic());
}
}
public static void main(String args[]) {
printFileds(InnerClass.class);
}
}
Output
Field: this$0, isSynthetic: true
Synthetic methods
Just like how the compiler generate synthetic fields, it will generate synthetic methods.
Let’s see it with an example.
SyntheticMethodDemo.java
public class SyntheticMethodDemo {
public class InnerClass {
private int a = 10;
private int b = 20;
}
public int getA() {
return new InnerClass().a;
}
public int getB() {
return new InnerClass().b;
}
}
Let’s compile above program.
$javac SyntheticMethodDemo.java
$
$ls *class
SyntheticMethodDemo$InnerClass.class SyntheticMethodDemo.class
As you see above snippet
two .class files generated. Let’s decompile the class ‘SyntheticMethodDemo$InnerClass.class’
and confirm the compiler generated methods.
$javap SyntheticMethodDemo\$InnerClass.class
Compiled from "SyntheticMethodDemo.java"
public class SyntheticMethodDemo$InnerClass {
final SyntheticMethodDemo this$0;
public SyntheticMethodDemo$InnerClass(SyntheticMethodDemo);
static int access$000(SyntheticMethodDemo$InnerClass);
static int access$100(SyntheticMethodDemo$InnerClass);
}
We can confirm the synthetic methods using Java code like below.
SyntheticMethodDemo.java
package com.sample.app;
import java.lang.reflect.Method;
public class SyntheticMethodDemo {
public class InnerClass {
private int a = 10;
private int b = 20;
}
public int getA() {
return new InnerClass().a;
}
public int getB() {
return new InnerClass().b;
}
private static <T> void printMethods(Class<T> clazz) {
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println("Field: " + method.getName() + ", isSynthetic: " + method.isSynthetic());
}
}
public static void main(String args[]) {
printMethods(InnerClass.class);
}
}
Output
Field: access$0, isSynthetic: true
Field: access$1, isSynthetic: true
Synthetic constructors
Let’s add a constructor to the inner class and confirm the existence of synthetic constructor.
SyntheticConstructorDemo.java
public class SyntheticConstructorDemo {
private InnerClass innerClazz = new InnerClass();
public class InnerClass {
private InnerClass() {
}
}
}
Let’s compile above class.
$javac SyntheticConstructorDemo.java
$
$ls *class
SyntheticConstructorDemo$1.class SyntheticConstructorDemo$InnerClass.class SyntheticConstructorDemo.class
Decompile the classes and confirm the same.
$javap SyntheticConstructorDemo.class
Compiled from "SyntheticConstructorDemo.java"
public class SyntheticConstructorDemo {
public SyntheticConstructorDemo();
}
$
$
$javap SyntheticConstructorDemo\$1.class
Compiled from "SyntheticConstructorDemo.java"
class SyntheticConstructorDemo$1 {
}
$
$
$
$javap SyntheticConstructorDemo\$InnerClass.class
Compiled from "SyntheticConstructorDemo.java"
public class SyntheticConstructorDemo$InnerClass {
final SyntheticConstructorDemo this$0;
SyntheticConstructorDemo$InnerClass(SyntheticConstructorDemo, SyntheticConstructorDemo$1);
}
We can get the information about synthetic constructor programmatically too.
SyntheticConstructorDemo.java
package com.sample.app;
import java.lang.reflect.Constructor;
public class SyntheticConstructorDemo {
private InnerClass innerClazz = new InnerClass();
public class InnerClass {
private InnerClass() {
}
}
private static <T> void printConstructors(Class<T> clazz) {
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println("name: " + constructor.getName() + ", isSynthetic: " + constructor.isSynthetic());
}
}
public static void main(String args[]) {
printConstructors(InnerClass.class);
}
}
Output
name: com.sample.app.SyntheticConstructorDemo$InnerClass, isSynthetic: false
name: com.sample.app.SyntheticConstructorDemo$InnerClass, isSynthetic: true
Reference
https://docs.oracle.com/javase/specs/jls/se8/html/jls-13.html
You may like
Initial heap size set to a larger value than the maximum heap size
No comments:
Post a Comment