1

Тема: Дженерики. Несумісність сумістних об'єктів

Вітаю!
Виникла складність з дженеріком так як не докінця їх розумію.
Програма виконується по плану, але зупиняюсь на тому, що не можу описати далі код так як типи невідповідні. В методі blockView класу TovarListBild який наслідується з класу MyBildActivity я отримаю потрібний мені об'єкт типу ServerTovarList (який наслідує ServerAnswer) в коді він записаний як обєкт типу ServerAnswer. Як правельно описати метод TovarListBild.blockView() щоб в ньому опрацьовувати результат вже як тип ServerTovarList.
Клас де є проблема:

public class TovarListBild extends MyBildActivity {
    TovarListBild(){ super(); }
    ServerTovarList stl;

    @Override
    public void blockView( ServerAnswer sc) {
        System.out.println("work");
        System.out.println("serverAnswer = " + sc);//влогах отримаю "serverAnswer = com.example.test.conect.ServerTovarList@e33c141" те що і потрібно мені.
        
        //але неможу записати це в такій формі.
        ServerTovarList stl = sc;//ПОМИЛКА!!! - Incompatible types. Found: 'com.example.test.conect.ServerAnswer', required: 'com.example.test.conect.ServerTovarList'
    }
}

Все починається з цього класу:

public class TovarListActivity extends AppCompatActivity {
    User user;
    Context context = this;
    TovarListActivity TLA = TovarListActivity.this;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tovar_list);

    user = new User(getSharedPreferences("User", MODE_PRIVATE));
    
    ArrayList<String> otherParam = new ArrayList<String>();
        otherParam.add("");

        TovarListBild tlb = new TovarListBild();
        tlb.bild(TLA, context, user.getUserUrlIndentificator(), "tovar_list", otherParam);
    }
}

Клас який наслідує клас TovarListBild

public abstract class MyBildActivity<PA extends AppCompatActivity, SC extends ServerAnswer> {
    Context context;
    String user;
    MyBildActivity mba = MyBildActivity.this;
    PA PA;//parent activity //посилання на бітьківський обєкт
    MyError myError;
    SC sc;


    public void bild(PA PA, Context context, String user, String nameGetId, ArrayList<String> parametrs){
        ... запит на сервер ...
    }

    //даний метод запускається коли сервер відповідає
    public void resultServer(SC sc){
        this.sc = sc;

        if (sc.conectStatus){ blockView(this.sc); }else{ /*error*/ }
    }

    public abstract void blockView(SC sc);
}

2

Re: Дженерики. Несумісність сумістних об'єктів

Це дуже добре, що ви поділились кодом, але було б ще краще, якби ви ним поділились повністю. Тобто показали всі ваші класи (ServerAnswer та ServerTovarList теж), як вони оголошені і кого наслідують. Натомість функції, що не мають відношення до спричинення проблеми можете прибрати, щоб більш чисто бачити дерево класів. Я не експерт з Java, але припускаю, що проблема у дженериках. А саме у тому, що SC не гарантує, що його можна призначити ServerTovarList, така гарантія є лише для класу ServerAnswer. Загалом, я не дуже розумію навіщо вам тут взагалі дженерики, чого ви хочете досягти використовуючи їх?

Подякували: ShadowTigr1

3

Re: Дженерики. Несумісність сумістних об'єктів

Використав дженерики та наслідування тому що кілька десятків класів використовують одну і туж саму структуру з відміностями лише у отримані відповіді сервера та виведені контента на екран.

Повна картина така:
Стартовий клас

public class TovarListActivity extends AppCompatActivity {
    User user;
    Context context = this;
    TovarListActivity TLA = TovarListActivity.this;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tovar_list);

        user = new User(getSharedPreferences("User", MODE_PRIVATE));
    
        ArrayList<String> otherParam = new ArrayList<String>();
        otherParam.add("");

        TovarListBild tlb = new TovarListBild();
        tlb.bild(TLA, context, user.getUserUrlIndentificator(), "tovar_list", otherParam);
    }
}

Наступний клас викликаний попереднім. В цьому класі в методі blockView і є проблема в отримані даних. blockView є наслідуваним методом з класу MyBildActivity

public class TovarListBild extends MyBildActivity {
    TovarListBild(){ super(); }
    ServerTovarList stl;

    @Override
    public void blockView( ServerAnswer sc) {
        System.out.println("work");
        System.out.println("serverAnswer = " + sc);//в логах отримаю "serverAnswer = com.example.test.conect.ServerTovarList@e33c141" те що і потрібно мені.
        
        //але неможу записати це в такій формі.
        ServerTovarList stl = sc;//ПОМИЛКА!!! - Incompatible types. Found: 'com.example.test.conect.ServerAnswer', required: 'com.example.test.conect.ServerTovarList'
    }
}

Клас MyBildActivity унаслідують інші класи подібні класу TovarListBild

public abstract class MyBildActivity<PA extends AppCompatActivity, SC extends ServerAnswer> {
    Context context;
    String user;
    MyBildActivity mba = MyBildActivity.this;
    PA PA;//parent activity //посилання на бітьківський обєкт
    MyError myError;
    SC sc;

    //метод для запиту на сервер
    public void bild(PA PA, Context context, String user, String nameGetId, ArrayList<String> parametrs){
        this.context = context;
        this.PA = PA;
        this.user = user;

        new Thread(new Runnable() {
            public void run() {
                ServerParametrs2 sp2 = new ServerParametrs2();//класс для передачі параметрів в клас Server
                sp2.mba = mba;
                sp2.paramList = parametrs;
                Server server = new Server();//клас для звязку із сервером
                server.setParametrs2(sp2);
                server.download(nameGetId, user);
            }
        }).start();
    }

    //даний метод запускається коли сервер відповідає
    //нижче у класі Server та MyCallback підставляються різні типи даних тому я використовую тут дженерик
    public void resultServer(SC sc){
        this.sc = sc;

        if (sc.conectStatus){ blockView(this.sc); }else{ /*error*/ }
    }

    public abstract void blockView(SC sc);
}

Клас для спілкування із сервером

public class Server{
    private Retrofit retrofit;
    private GetRequest_Interface request;

    ..........

    public String download(String type_url, String user_Url_Inden){
        userUrlInden = user_Url_Inden;
        typeUrl = type_url;
        try{
            switch(type_url){
                case "tovar_list":
                     retrofirBuild();
                     conectR_tovar_list();

               ..... список різних запросів .....
            }
        }catch (IOException e){
            conectStatus = false;
            resultConect = e.getMessage();
        }

        return resultConect;
    }

    private void retrofirBuild(){
        retrofit = new Retrofit.Builder()
                .baseUrl (SN) // Установить URL-адрес сетевого запроса
                .addConverterFactory (GsonConverterFactory.create ()) 
                .build();

        request = retrofit.create(GetRequest_Interface.class);
    }

    private void conectR_tovar_list(){
        String kat;
        try{
            kat = sp2.paramList.get(0);
        }catch(Exception e){
            kat = "";
        }
        ServerTovarList serverTovarList = new ServerTovarList();

        Call<ServerTovarList> call = request.tovarList(getServerName(typeUrl) + kat);
        call.enqueue(new MyCallback<ServerTovarList>(sp2, serverTovarList));
    }
}

В цьому класі я і починаю працювати з дженеріками. Для опрацюваня дженеріка прийшлось вказати наслідування <SC extends ServerAnswer> так як без цього у мене не виходило вказати sc.conectStatus, sc.error, sc.result

public class MyCallback<SC extends ServerAnswer> implements Callback<SC> {
    ServerParametrs2 sp2;
    SC sc;

    MyCallback(ServerParametrs2 sp2, SC sc){
        super();
        this.sp2 = sp2;
        this.sc = sc;
    }

    public void onResponse(Call<SC> call, Response<SC> response){
        if(response.isSuccessful()){
            sc = response.body();

            if(sc.error == null || sc.error.isEmpty()){
                sc.conectStatus = true;
            }else{
                sc.conectStatus = false;
                sc.result = sc.error;
            }
        }else{
            try {} catch (Exception e) {}

            sc.conectStatus = false;
            sc.result = "";
        }

        sp2.mba.resultServer(sc);
    }

    public void onFailure(Call<SC> call, Throwable t){
        sp2.mba.showError( " no connect server ");
    }
}

Обидва класи працюють з відповідю сервера у форматі JSON

//унаслідується іншими класами для формату JSON
public class ServerAnswer {
    @SerializedName("error") @Expose public String error;

    public boolean conectStatus;
    public String result;
}


//один з багатьох класів що унаслідують клас ServerAnswer 
public class ServerTovarList extends ServerAnswer {
    ServerTovarList(){super();}

    @SerializedName("tovar")  @Expose public ServerTovarListChild tovar;
}

4

Re: Дженерики. Несумісність сумістних об'єктів

Проблема вирішена
Все що потрібно було це привести ServerAnswer до типу ServerTovarList.

public class TovarListBild extends MyBildActivity {
    TovarListBild(){ super(); }

    @Override
    public void blockView( ServerAnswer sc) {
        ServerTovarList stl = (ServerTovarList )sc;

    }
}