1

I have a class User, only have two fields: id, name

package test;

public class User {
    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Then in the Main class, I tried to initialize the User object with two different approach:

package test;

/**
 * @author lhuang
 */
public class Main {
    public static void main(String[] args) {
        User u = new User() {
            {
                setId(1l);
                setName("LHuang");
            }
        };

        System.out.println(u.getClass());

        User u2 = new User();
        u2.setId(1l);
        u2.setName("LHuang");
        System.out.println(u2.getClass());
    }
}

then I can get the output

class test.Main$1
class test.User

The interesting is why the u class is the inner class type of Main? But actually I still can use the u.getId() and u.getName() method.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
Liping Huang
  • 4,378
  • 4
  • 29
  • 46
  • 1
    You created an anonymous class. – Jeroen Vannevel May 29 '15 at 14:23
  • This is the so called "double brace initialisation anti-pattern". You have just discovered why it's an anti-pattern. – Boris the Spider May 29 '15 at 14:34
  • I don't think this question is a duplicate! The actual answer to the questioners last sentences are about the *naming* of inner classes. The questions are related but different. I'm afraid I cannot add the following as an answer because the question is closed, but here it is: The inner class is not of type `Main` but only its name is based on it because `Main` is the enclosing type. This behavior is specified in [JLS §13.1](https://docs.oracle.com/javase/specs/jls/se8/html/jls-13.html#jls-13.1). – siegi May 29 '15 at 15:07

2 Answers2

6

You're creating an anonymous class that extends from User here:

User u = new User() { //<-- this open bracket defines a new class
        {
            setId(1l);
            setName("LHuang");
        }
    };
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
2

This

User u = new User() { // here's your derived class
        {             // here's the initialiser block
            setId(1l);
            setName("LHuang");
        }
    };

creates a new anonymous subclass of User (the outer set of braces), and then defines an initialiser block within that (the inner set of braces).

It's often advised to avoid the above construction for reasons of clarity (not many people are aware of how it works), and since you're creating an inner class, it'll have an implicit reference to the outer class. This can cause issues for garbage collection and serialisation.

Having said that, I would use the above sparingly (e.g. for setting up test collections in unit tests etc. due to its conciseness)

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440