Разница между новым тестом() и новым тестом() { }

В чем разница между этими двумя способами создания новых объектов класса следующим образом:

Test t1=new Test();
Test t2=new Test(){ };

Когда я попробовал следующий код, я увидел, что оба объекта могут получить доступ к методу foo(), но t2 не может получить доступ к variable x (variable x не может быть разрешен):

public class Test
{ 
    int x=0;
    public void foo(){ }

    public static void main (String args[])
    {
        Test t1=new Test();
        Test t2=new Test(){ };
        t1.x=10;
        t2.x=20;
        t1.foo();
        t2.foo();
        System.out.println(t1.x+" "t2.x);
    }
}

person Crusaderpyro    schedule 04.03.2014    source источник
comment
Я бы сказал, что нет, иначе второй способ позволяет вам переопределять методы в родительском классе без необходимости создавать выделенный подкласс.   -  person MadProgrammer    schedule 04.03.2014
comment
Если вы сделаете его компилируемым, преобразовав t1.x+" "t2.x в t1.x+" "+t2.x, он отлично скомпилируется.   -  person JB Nizet    schedule 04.03.2014
comment
@Ankur Shanbhag Это недопустимое редактирование.   -  person Suresh Atta    schedule 04.03.2014
comment
@sᴜʀᴇsʜᴀᴛᴛᴀ: Эй, брат, я не видел твоего поста до того, как внес изменения. Я не хотел лишить вас кредита. На самом деле я внес изменение, поскольку оно не имело ничего общего с концепцией внутреннего класса.   -  person Ankur Shanbhag    schedule 04.03.2014
comment
@AnkurShanbhag Никаких проблем, но не делайте таких правок. Вы можете увидеть влияние в этом случае :)   -  person Suresh Atta    schedule 04.03.2014
comment
@sᴜʀᴇsʜᴀᴛᴛᴀ: Конечно. Я буду осторожен со своими правками.   -  person Ankur Shanbhag    schedule 04.03.2014
comment
@AnkurShanbhag Просто делюсь. Я получил предупреждение от Модов даже в первые дни редактирования;)   -  person Suresh Atta    schedule 04.03.2014
comment
Дополнительно можно сказать, что второй метод просто не является способом создания нового объекта. Это специфично для Java, т.е. вы не можете сделать это в C#.   -  person Dims    schedule 05.03.2014


Ответы (7)


Test t2=new Test(); создаст объект класса Test.

Но Test t2=new Test(){ }; создаст объект подкласса теста (т.е. в данном случае анонимный внутренний класс).

вы можете предоставить реализацию для любого метода, например

Test t2=new Test(){ 
public void foo(){ System.out.println("This is foo");}
};

так что когда метод foo() вызывается из объекта t2, он печатает This is foo.

Дополнение

Ошибка времени компиляции в вашем коде связана с отсутствием оператора конкатенации

System.out.println(t1.x+" "+t2.x);
                          ###
person eatSleepCode    schedule 04.03.2014
comment
@eatSleepCode. Не совсем. Но, конечно, он не заслуживает 5 голосов в текущем состоянии. Есть только небольшая ошибка, которую вы должны исправить. - person Rohit Jain; 04.03.2014
comment
@RohitJain не является t2 объектом класса test? - person eatSleepCode; 04.03.2014
comment
@eatSleepCode Что ж, t2 instanceof Test вернет true, но это не значит, что new Test() { } создает объект Test. Нет, это не так. Объект подкласса всегда является instanceof всеми своими суперклассами. - person Rohit Jain; 04.03.2014
comment
Поскольку новый тест(){ }; ничего не отменяет... разве это не тот же самый класс? - person Solace; 04.03.2014
comment
@Solac Нет, совсем нет. Попробуйте скомпилировать класс, вы увидите два сгенерированных файла класса. Один с именем Test$1 - person Rohit Jain; 04.03.2014
comment
@eatSleepCode Точно. - person Rohit Jain; 04.03.2014
comment
Возможно, вы захотите пройти через это, это и этот мой ответ. - person Rohit Jain; 04.03.2014
comment
Вы хотите добавить вывод t2.getClass() к своему ответу? Это может сделать его более понятным (вместо комментария о создании двух .class файлов). - person ashes999; 04.03.2014
comment
@eatSleepCode Чтобы завершить ответ, вы можете объяснить, почему x недоступен из подкласса и как сделать его доступным. - person hopia; 05.03.2014

Тип времени выполнения обеих ссылок будет другим. Пытаться:

System.out.println(t1.getClass());  // class Test
System.out.println(t2.getClass());  // class Test$1

Вы увидите другой вывод. Причина в том, что выражение new Test() { } создает экземпляр анонимного подкласса Test. Итак, Test$1 является подклассом Test.

Теперь причина, по которой вы получаете эту ошибку, заключается в том, что вам не хватает знака +:

System.out.println(t1.x + " " + t2.x);
                              ^

Вы можете найти более подробную информацию в этом сообщении и этот пост

person Rohit Jain    schedule 04.03.2014
comment
Если бы x был закрытым, то t2 не смог бы его увидеть? - person Cruncher; 04.03.2014
comment
@Cruncher Да, не будет. В текущем коде, поскольку метод main находится в самом классе, казалось бы, он может получить доступ, но если вы переместите его за пределы класса, ни t1, ни t2 не смогут получить доступ к x. - person Rohit Jain; 04.03.2014
comment
Ты прав. В этом случае я не думаю, что упоминание того факта, что x имеет модификатор по умолчанию, уместно. Для любого модификатора либо t1 и t2 могут его видеть, либо ни один из них. - person Cruncher; 04.03.2014

test t1=new test();

Это создаст новый экземпляр класса test

test t2=new test(){ };  

Это анонимный внутренний класс, который расширяет класс test.

person Ankur Shanbhag    schedule 04.03.2014

Test t1=new Test();

Здесь вы создаете экземпляр класса Test и назначаете его t1

Test t2=new Test(){ };

Здесь вы создали анонимный подкласс Test, создали его экземпляр и назначили t2.

И, вы сделали ошибку здесь в следующей строке, исправили ее, вы пропустили +

System.out.println(t1.x + " " + t2.x);
person Abimaran Kugathasan    schedule 04.03.2014

a)

 Test t1=new Test();

Делая это, вы создаете объект класса Test, вызывая конструктор по умолчанию

b)

Test t2=new Test(){ };

Делая это, вы создаете объект класса, который расширяет тестовый класс, этот класс не имеет имени и, следовательно, называется «Анонимный внутренний класс», например.

     Test t2=new Test(){ 
// this is the body of the anonymous(un-named) class 
//you can overide the method foo() here
// you can write more methods here but you will not be able to call them 
// for example
public void doSomething(){}
};

doSomething() недоступен снаружи, так как t2, т.е. ссылка (указатель) на этот объект (объект анонимного внутреннего класса, который расширяет Test), понимает только метод foo(), поскольку он является ссылкой родительского класса

doSomething() можно вызвать, только если вы сделаете это

  Test t2=   new Test(){
            public void foo()
            {
              doSomething();


            }
            public void doSomething(){
                  System.out.println("Do Something");
            }

        };

то есть явно вызывать doSomething() в foo(), а foo() доступен снаружи

t2.foo();

Примечание. Пожалуйста, напишите имя класса правильно, первая буква класса должна быть заглавной, например

public class Test{}

Когда вы начнете писать огромные куски кода, это поможет вам и другим, поскольку сделает ваш код читабельным.

person Oliver    schedule 05.03.2014
comment
Я знаю, что имена классов всегда начинаются с заглавной буквы. Это было просто создано, чтобы проверить разницу между двумя методами. В любом случае, спасибо за подробный ответ. - person Crusaderpyro; 05.03.2014

вам не хватает оператора + в строке ниже, попробуйте это

System.out.println(t1.x+" "t2.x);

использовать это

System.out.println(t1.x+" "+t2.x);
person Rishi Dwivedi    schedule 04.03.2014

Test t2=new Test();` 

создаст объект класса Test.

Test t2=new Test(){ };

создаст объект подкласса теста (т.е. анонимный внутренний класс в этом случае).

Test t2=new Test(){ 
public void foo(){ System.out.println("foo");}
};

когда метод foo() вызывается из объекта t2, он печатает foo.

person CCUSER    schedule 05.03.2014