[Java] Как передать класс

675
2
Доброго времени суток.

Такие дела:
Код:
    public void changeBlock(Block changedBlock, Class <? extends Block> changedBlockClass, int toChangeBlockId) {
        Block.blocksList[toChangeBlockId] = null;
        changedBlock = new changedBlockClass(toChangeBlockId, Material.portal);
        GameRegistry.registerBlock(changedBlock, Block.blocksList[toChangeBlockId].getUnlocalizedName());
        Block.blocksList[toChangeBlockId] = changedBlock;
    }

Проблема в том, что компилятор отказывается проглатывать changedBlockClass(toChangeBlockId, Material.portal).

Так вызываю:
Код:
changer.changeBlock(changedPortalBlock, ChangedPortalBlock.class, Block.endPortal.blockID);

Мб есть какой-то другой способ передать класс?
 
Скажем так - ты пытаешься передать тип(а передаешь класс) это раз, а два - даже если правильно передашь типа, то просто new тебе не поможет, так-что пишешь ересь.
 
Мне на ум приходит только:
Код:
    public void changeBlock(Block changedBlock, int toChangeBlockId) {
        Block.blocksList[toChangeBlockId] = null;
        
        switch (toChangeBlockId) {
            case 119: changedBlock = new ChangedPortalBlock(toChangeBlockId, Material.portal); break;
        }
        
        GameRegistry.registerBlock(changedBlock, Block.blocksList[toChangeBlockId].getUnlocalizedName());
        Block.blocksList[toChangeBlockId] = changedBlock;
    }
 
Код:
Class blockClass = changedBlock.getClass();
/* А вот нужный тебе конструктор */
Block newBlock = blockClass.getConstructor(int.class /*or your params*/).newInstance(blockID);
Рефлексия.
 
Oldestkon написал(а):
Код:
Class blockClass = changedBlock.getClass();
/* А вот нужный тебе конструктор */
Block newBlock = blockClass.getConstructor(int.class /*or your params*/).newInstance(blockID);
Рефлексия.

В таком случае Class blockClass = changedBlock.getClass(); выбивает null. Пожалуй, повременю я с этой рефлексией, ибо сейчас не хватает знаний, дабы понять её.
switch мне в помощь.
 
Ну так возьми свой метод, выше.
Код:
 public void changeBlock(Block changedBlock, Class <? extends Block> changedBlockClass, int toChangeBlockId) {
        Block.blocksList[toChangeBlockId] = null;
        /* таки вот */
        changedBlock = changedBlockClass.getConstructor(int.class).newInstance(toChangeBlockId);
        GameRegistry.registerBlock(changedBlock, Block.blocksList[toChangeBlockId].getUnlocalizedName());
        Block.blocksList[toChangeBlockId] = changedBlock;
    }
Рефлексия не такая сложная на самом деле. Всяко лучше свитче-костылей.
Про гетКласс писал на коленке, посмотрю что там вылезает.

Алсо, поставь пчелку (System.out.println("something")) на проверку твоего changedBlock на null. Метод getClass() в принципе не может никоим образом вернуть тебе null, ошибка возникает раньше.
 
Oldestkon написал(а):
Ну так возьми свой метод, выше.
Код:
 public void changeBlock(Block changedBlock, Class <? extends Block> changedBlockClass, int toChangeBlockId) {
        Block.blocksList[toChangeBlockId] = null;
        /* таки вот */
        changedBlock = changedBlockClass.getConstructor(int.class).newInstance(toChangeBlockId);
        GameRegistry.registerBlock(changedBlock, Block.blocksList[toChangeBlockId].getUnlocalizedName());
        Block.blocksList[toChangeBlockId] = changedBlock;
    }
Рефлексия не такая сложная на самом деле. Всяко лучше свитче-костылей.
Про гетКласс писал на коленке, посмотрю что там вылезает.

Алсо, поставь пчелку (System.out.println("something")) на проверку твоего changedBlock на null. Метод getClass() в принципе не может никоим образом вернуть тебе null, ошибка возникает раньше.

Да, стоило обращается к передаваемому классу, а уже из него тянуть конструктор.

Как-то так:
Код:
    public void changeBlock(Block changedBlock, Material material, Class <? extends Block> changedBlockClass, int toChangeBlockId) {
        Block.blocksList[toChangeBlockId] = null;
        
        try {
            changedBlock = changedBlockClass.getConstructor(int.class, Material.class).newInstance(toChangeBlockId, material);
        } catch(InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {}
        
        GameRegistry.registerBlock(changedBlock, Block.blocksList[toChangeBlockId].getUnlocalizedName());
        Block.blocksList[toChangeBlockId] = changedBlock;
    }

И так вот вызываю:
Код:
        try {
            
            changer.changeBlock(changedPortalBlock, Material.portal, ChangedPortalBlock.class, Block.endPortal.blockID);
            
        } catch (IllegalArgumentException | SecurityException e) {}

try-catch конечно мозолят глаза, но это лучше, чем каждый раз соваться в класс changer'а и дописывать новый id, спасибо.
 
Ну трай-кэтч это обязательный атрибут в данном случае. Может такого конструктора не оказаться, а экспшн кидать надо.
Можно было ещё через throws сделать, но лаконичнее оставить try-catch внутри метода, ибо он будет большую часть времени закрыт от глаз.
 
Oldestkon написал(а):
Ну трай-кэтч это обязательный атрибут в данном случае. Может такого конструктора не оказаться, а экспшн кидать надо.
Можно было ещё через throws сделать, но лаконичнее оставить try-catch внутри метода, ибо он будет большую часть времени закрыт от глаз.
Понятное дело, ещё раз спасибо.
p.s. - оказалось, что вызывать можно и try-catсh, т.е. просто так:
Код:
changer.changeBlock(changedPortalBlock, Material.portal, ChangedPortalBlock.class, Block.endPortal.blockID);

Можно закрывать.
 
Скажем так, если я правильно понял, что ты хочешь сделать, то ты делаешь неимоверную ересь.
Почему просто не написать
Block.blockList[119] = new MyPortal() ?
[merge_posts_bbcode]Добавлено: 13.05.2014 14:54:09[/merge_posts_bbcode]

Зачем передавать класс и в нём делать инстанс рефлекшном? -__-...
Если можно просто передать инстанс твоего блока.
 
anti344 написал(а):
Скажем так, если я правильно понял, что ты хочешь сделать, то ты делаешь неимоверную ересь.
Почему просто не написать
Block.blockList[119] = new MyPortal() ?
[merge_posts_bbcode]Добавлено: 13.05.2014 14:54:09[/merge_posts_bbcode]

Зачем передавать класс и в нём делать инстанс рефлекшном? -__-...
Если можно просто передать инстанс твоего блока.
Ты правильно понял)

Сделал отдельный метод:
Код:
    private static void changeVanillaBloks() {
        Block.blocksList[Block.endPortal.blockID] = null;
        Block.blocksList[Block.endPortal.blockID] = new ChangedPortalBlock(119, Material.portal);
    }

Теперь буду в нем жеш обнулять каждый новый блок, а затем подставлять свой класс.
Можно закрывать.
 
Лол. А можно так. Гораздо эффективнее.
Код:
 private static void changeBlock(Block from, Block to) {
        Block.blocksList[from.blockID] = to;  
//Все блоки обьявлены статично - существуют в одном экземпляре, так что так можно делать.
    }
Меня смущает одно:
Ты меняешь, допустим, камень (ID = 1) на свой блок (ID = N), в массиве ты меняешь по индексу первый элемент. А в движке игры нередко используется прямой поиск блоков через массив. И когда игра попытается найти твой блок в массиве по ID из твоего класса - это будет нифига не элемент с индексом 1.

P.S. Практика на костылях - очень плохая практика.
 
Что-то я не очень понимаю, о чем ты говоришь.

И когда игра попытается найти твой блок в массиве по ID из твоего класса - это будет нифига не элемент с индексом 1.
Индекс(id) так и останется 192:
Код:
System.out.println(Block.blocksList[119]);

[STDOUT] flymod.blocks.ChangedPortalBlock@47128fa3
Или ты не об этом?
 
Дело в том, что в массиве блоки хранятся не в случайном порядке и не в порядке заполнения, а по ID.
Допустим:

Код:
stone.ID = 1;
blocks[stone.ID] = stone; //blocks[1] - stone
myblock.ID = 132;
blocks[stone.ID] /* мы же его хотим поменять, так? */ = myblock;

blocks[myblock.ID] - или null, или твой блок, но доступ к элементу, который ты заменил с камня на свой блок ты уже не получишь. Ибо myblock.ID = 132, а мы меняли элемент с индексом 1.
Т.е. получается что ты как бы под ID 1 хранишь блок, у которого ID 132.
 
Oldestkon написал(а):
Дело в том, что в массиве блоки хранятся не в случайном порядке и не в порядке заполнения, а по ID.
Допустим:

Код:
stone.ID = 1;
blocks[stone.ID] = stone; //blocks[1] - stone
myblock.ID = 132;
blocks[stone.ID] /* мы же его хотим поменять, так? */ = myblock;

blocks[myblock.ID] - или null, или твой блок, но доступ к элементу, который ты заменил с камня на свой блок ты уже не получишь. Ибо myblock.ID = 132, а мы меняли элемент с индексом 1.
Т.е. получается что ты как бы под ID 1 хранишь блок, у которого ID 132.
Возвращаясь к моему случаю:
Код:
        Block.blocksList[Block.endPortal.blockID] = null;
        Block.blocksList[Block.endPortal.blockID] = new ChangedPortalBlock(119, Material.portal);
Block.endPortal.blockID вернет нам 119. Т.е. я под ID 119 храню блок с ID 119

Могу писать так, если id эндер-портала вдруг изменится.
Код:
Block.blocksList[Block.endPortal.blockID] = new ChangedPortalBlock(Block.endPortal.blockID, Material.portal);
Но в таком случае мне очень хочется сделать отдельный метод. Неужто рефлекшн так плох?
 
f1rSt1k написал(а):
Медленный просто и не красивый.
Аргумент однако. А нет ли какой-нибудь таблицы с относительным временем работы того или иного метода?

Не красиво будет, когда я буду постоянно прописывать:
Код:
Block.blocksList[Block.***.blockID] = null;
 
@f1rSt1k
Офигеть аргумент. Если бы ты использовал этот метод каждый тик там, где он безусловно выполняется и не раз, тогда да. Надо видеть разницу, где скорость влияет на производительность, а где нет. Так что здесь это нифига не аргумент, хотя сам факт я не отрицаю.

@Тry4W
Ну выбор за тобой, сидеть и при каждом новом блоке пополнять метод новыми строчками, строча индусокод, или делать что-то через НЕКРАСИВУЮ и МЕДЛЕННУЮ рефлексию, которая сделает всё сама.
Особенно классно было бы, если бы таких блоков были сотни или пришлось бы делать это с блоками из другого мода.
 
Так, а чем это рефлексия сокращает размер кода в этом случае?
 
anti344 написал(а):
Так, а чем это рефлексия сокращает размер кода в этом случае?
Необходимо каждый раз, для каждого изменяемого блока делать:
Код:
Block.blocksList[Block.***.blockID] = null;

Иначе будет конфликт id.
В итоге эти две строчки можно сунуть в метод и просто вызывать его, передавая на вход материал, класс и id блока, который я собираюсь заменить.
 
Назад
Сверху