Tuesday 19 October 2021

Synthetic constructs in Java

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

Interview Questions

Initial heap size set to a larger value than the maximum heap size

Is below statement compile?

Versioning History of Java

Understanding ConcurrentModificationException in Java

Remove oldest entry from the map

No comments:

Post a Comment