Java что располагается внутри фигурных скобок

217
23 июля 2018, 22:20

Встретил вот такой интересный участок кода, но ничего не могу про него найти:

JPanel contentPane = new JPanel() {             
            BufferedImage [] img = new BufferedImage[] { // вот это поле
                ImageIO.read(new File("image/_1.png")),
                ImageIO.read(new File("image/_2.png"))
            };
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.drawImage(img[0],0,0,null);
            }
        };

Почему после конструкции new JPanel() внутри фигурных скобок присутствуют переменные? Как это называется?

Answer 1

То, с чем мы здесь имеем дело -- это не анонимные поля, это описание анонимного класса, который является потомком класса JPanel. То, что следует за вызовом конструктора new JPanel() в фигурных скобках -- это фактически описание нового класса; вы его описываете и сразу же создаете экземпляр этого нового класса и присваиваете его переменной contentPane типа JPanel (это возможно, поскольку новый клаcc - дочерний по отношению к JPanel), но вы не можете создавать переменные нового типа, поскольку у нового класса нет своего имени.

Как и любой дочерний класс, новый класс (хоть анонимный, хоть нет) может содержать дополнительные поля и методы, может также переопределять методы родительского класса. Как и при описании любого класса, переменные могут быть инициализированы выражениями, которые вычисляются в момент создания экземпляра класса. Выражения могут содержать вызовы методов, эти методы будут вызываться в момент инициализации. Ваш код

BufferedImage [] img = new BufferedImage[] { // вот это поле
            ImageIO.read(new File("image/_1.png")),
            ImageIO.read(new File("image/_2.png"))
        };, 

занимается именно этим -- создается массив из двух элементов (не анонимный -- у него есть имя -- img!), для каждого из них вызывается метод read(), который возвращает значение, которое и присваивается элементу массива.

Анонимный класс отличается от нормального тем, что у него нет имени, а значит, нельзя описать переменную такого класса, а значит, нет честного способа обратиться извне к тем его полям и методам, которые не описаны в родительском классе. Но описанные в нем методы (в том числе переопределенные методы родительского класса) вполне могут к ним обращаться, например, в вашем коде это g.drawImage(img[0],0,0,null);.

Так что конструкция вида

MyClass myVar = new MyClass() {
   int number = 123;
   String name = new String("Это объект № ");
   @Override
   public String toString() {
     return name + number;
   }  
   public void foolish() {
     System.out.println("Этот метод не может быть вызван");
   }
}

равносильна описанию

class NewClass extends MyClass {
   int number = 123;
   String name = new String("Это объект № ");
   @Override
   public String toString() {
     return name + number;
   }  
   public void foolish() {
     System.out.println("Этот метод не может быть вызван");
   }
}
NewClass myVar = new NewClass();

за исключением того, что в случае обычного класса вы можете вызвать вновь описанный метод

myVar.foolish();

а в случае анонимного класса вы этого сделать не можете, поскольку переменная myVar относится к типу MyClass, который такого метода не содержит.

Answer 2

Это не поля класса. Просто создаётся массив экземпляров класса BufferedImage. Вызов метода ImageIO.read(new File("image/_1.png")), скорее всего, возвращает экземпляр этого класса. Переписал ваш код для наглядности:

public class some { 
   public static void main(String[] args) {
        Other[] arrayOfOther = new Other[] {
            new Other(),
            new Other()
        };
    }
}
class Other{}

Update

Переписал для вас половину swing-a. Надеюсь будет понятней

import java.util.Arrays;
public class Test {
    public static void main(String[] args) {
        JPanel contentPane = new JPanel() {             
                BufferedImage [] img = new BufferedImage[] { // вот это поле
                    ImageIO.read(),
                    ImageIO.read()
                };
                protected void paintComponent(String s) {
                    super.paintComponent(s);
                    System.out.println("Я метод класса-наследника. И да, я имею доступ к массиву `img` " + Arrays.toString(img));
                }
            };        
        contentPane.paintComponent("");
    }
}
// "Оригинальный" класс JPanel. Понятия ни имеет о массиве `BufferedImage [] img`
class JPanel {
    protected void paintComponent(String s) {
        System.out.println("Я метод родительского класса. Меня вызвали. Ура");
    }
}
class BufferedImage {
    public String toString() {
        return "Красивая картинка";
    }
}
class ImageIO {
    static BufferedImage read() {
        return new BufferedImage();
    }
}

Попробуйте запустить эту программу.

READ ALSO
Не удаляется объект при связи @OneToMany Java Hibernate

Не удаляется объект при связи @OneToMany Java Hibernate

Не могу понять в чем может быть ошибка при удалении

201
Проблема получение данных с сайта

Проблема получение данных с сайта

Занимаюсь получением http запроса, я вроде как пробился на сайт, но получаю след ошибки:

197
Загрузка больших файлов через REST API

Загрузка больших файлов через REST API

Я пишу файловое хранилище и хочу улучшить его работуЗагружаются файлы большого размера, кроме этого, после загрузки надо запретить их изменение,...

185