# R8 Optimization: Class Reflection and Forced Inlining

DevFeed: [R8 Optimization: Class Reflection and Forced Inlining](<https://devfeed.tech/articles/r8-optimization-class-reflection-and-forced-inlining-20956.md>)

Original publisher: [Read original article](<https://jakewharton.com/r8-optimization-class-reflection-and-forced-inlining/>)

Published: 2019-09-25T00:00:00Z

Content type: article

Language: en

Sources: [Jake Wharton](<https://devfeed.tech/sources/jake-wharton.md>)

Topics: [R8](<https://devfeed.tech/topics/r8.md>), [Optimization](<https://devfeed.tech/topics/optimization.md>), [Android](<https://devfeed.tech/topics/android.md>), [obfuscation](<https://devfeed.tech/topics/obfuscation.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [code](<https://devfeed.tech/tags/code.md>), [inlining](<https://devfeed.tech/tags/inlining.md>), [obfuscation](<https://devfeed.tech/tags/obfuscation.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [r8](<https://devfeed.tech/tags/r8.md>)

## AI overview

This article explains how R8 optimizes Java class reflection in Android applications. It contrasts static class literals with instance getClass() calls, then describes how whole-program analysis can replace reflective calls with known class references and string constants. It also examines a case where method inlining is blocked by method-size limits and introduces forced inlining through R8 configuration rules compatible with ProGuard.

## Source excerpt

Note: This post is part of a series on D8 and R8, Android's new dexer and optimizer, respectively. For an intro to D8 read "Android's Java 8 support". For an intro to R8 read "R8 Optimization: Staticization". The previous post on R8 covered method outlining which automatically de-duplicated code. This was actually a detour from what I had promised was next at the end of the class constant operations post which preceded it. So let's get back on track. Class constant operations allow R8 to take calls such as MyActivity.class.getSimpleName() and replace it with the string literal "MyActivity". This was presented in the context of log tags, where you might write that expression instead of the string literal so that the tag always reflects the actual class name, even after obfuscation. This works great in a static context where the MyActivity.class literal is fixed, but it does not work when used on an instance. Instance reflection When dealing with an instance, the Class reference is obtained by calling getClass() instead of a MyActivity.class literal. This operation is not terribly expensive, but it is still a form of reflection. class MyActivity extends Activity { @Override void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String name = this.getClass().getSimpleName(); Log.e(name, "Hello!"); } } The getClass() API is just a normal method on every Object and appears as a normal invoke-virtual in bytecode. [0003d0] MyActivity.onCreate:(Landroid/os/Bundle;)V 0000: invoke-super {v1, v2}, Landroid/app/Activity;.onCreate:(Landroid/os/Bundle;)V 0003: invoke-virtual {v1}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; 0006: move-result-object v2 0007: invoke-virtual {v2}, Ljava/lang/Class;.getSimpleName:()Ljava/lang/String; 000a: move-result-object v2 Since R8 is performing whole-program analysis, it knows that there are no subtypes of MyActivity even though it's not marked as final. As a result, it can replace calls to this.getClass() with MyAct