【问题标题】:Why writing an Inner Private class inside <> bracket of outer class makes error?为什么在外部类的 <> 括号内编写内部私有类会出错?
【发布时间】:2020-11-14 16:45:06
【问题描述】:

我正在尝试将私有类插入外部类声明的括号(泛型)并得到下一个错误:“com.example.gridrecyclerview.RecyclerViewAdapter.VieHolder 在 com.example.gridrecyclerview.RecyclerViewAdapter 中具有私有访问权限”

将内部类更改为 public 时一切正常。有人可以解释我的问题。 附代码:

    package com.example.gridrecyclerview;

import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.List;
import java.util.Random;

public class RecyclerViewAdapter extends RecyclerView.Adapter <RecyclerViewAdapter.ViewHolder> {
    Context context;
    List<ModelItem> modelItemList;

    public RecyclerViewAdapter(Context context, List<ModelItem> modelItemList)
    {
        this.context = context;
        this.modelItemList = modelItemList;
    }

    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
    {
        View view = LayoutInflater.from(context).inflate(R.layout.rc_item,parent,false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position)
    {
        Log.e("onBindViewHolder ","onBindViewHolder");
        ModelItem modelItem = modelItemList.get(position);
        holder.firstNameTextView.setText(modelItem.getFirstName());
        holder.secondNameText.setText(modelItem.getLastName());
    }

    @Override
    public int getItemCount()
    {
        return modelItemList.size();
    }

    private class ViewHolder extends RecyclerView.ViewHolder
    {

        TextView firstNameTextView;
        TextView secondNameText;
        public ViewHolder(@NonNull View itemView)
        {
            super(itemView);
            firstNameTextView = itemView.findViewById(R.id.first_name);
            secondNameText = itemView.findViewById(R.id.second_name);
        }
    }
}

【问题讨论】:

  • 抛开泛型不谈,您认为您应该能够编写一个返回(或具有参数)非私有类型的公共方法吗?如果有人编写了public static PrivateClass getPrivateClassInstance() 的方法,您希望编译器对调用该方法的任何代码做什么?在您的情况下应用相同的逻辑。

标签: java generics private inner-classes


【解决方案1】:

您不能这样做,因为您将私有类传递给“RecyclerView.Adapter”类。也就是说,ViewHolder 类只能在 RecyclerViewAdapter 类中使用。

PS:您可以将这个类创建为一个新的类,然后通过“RecyclerView.Adapter”类传递它或将其更改为公共范围。

【讨论】:

  • 感谢您的回复。我知道我可以将它公开,一切都会正常工作,但我想了解为什么当前代码不起作用。您写道:*“您不能这样做,因为您将私有类传递给“RecyclerView.Adapter”类。换句话说,ViewHolder 类仅在 RecyclerViewAdapter 类中可用“*。 RecyclerViewAdapte 的签名是它的类的一部分吗?
  • 这里的问题与RecyclerViewAdapter类无关,问题是“RecyclerView.Adapter ”因为RecyclerViewAdapter.ViewHolder的范围,私有类实例仅在RecyclerViewAdapter类中可用为什么“RecyclerView.Adapter”“RecyclerViewAdapter.ViewHolder”类无法访问。是的,它看起来很奇怪,但在泛型中,虽然 RecyclerViewAdapter 扩展了 RecyclerView.Adapter 这并不意味着 RecyclerView.Adapter 在 RecyclerViewAdapter 的签名中。
【解决方案2】:

要回答这个问题,您应该知道在 Java 中使用泛型时幕后发生了什么,泛型在编译时被检查并且在运行时没有泛型类型,这称为类型擦除,当您编译程序时,所有泛型都是种姓到他们的特定类型。想象一下你的RecyclerView.Adapter 类如下:

public class Adapter<T> {
    T view;

    public T getView() {
        return view;
    }

    public void setView(T view) {
        this.view = view;
    }
}

想象一下,您已经像以前一样定义了 RecyclerViewAdapter 类:

现在让我们从两个角度来讨论这个问题:

  1. 程序员
  2. 编译器

作为一个程序员,想象在另一个类的某个地方,您创建了一个 RecyclerViewAdapter 类的实例,如下所示,并在该对象上调用 getView():

RecyclerViewAdapter recycler = RecyclerViewAdapter();
? object =  recycler.getView()

你把什么类型的对象放在这里而不是? 显然你不能放 RecyclerViewAdapter.ViewHolder 因为它对 RecyclerViewAdapter 是私有的,你不能在其他地方使用它。

现在让我们从编译器的角度考虑这个问题:

在编译泛型时,编译器使用擦除并将您的代码编译成如下内容:

RecyclerViewAdapter recycler = RecyclerViewAdapter();
? object =  (RecyclerViewAdapter.ViewHolder)recycler.getView();

在这里您可以看到编译器在编译时转换了对象的类型((RecyclerViewAdapter.ViewHolder)recycler.getView())。但是编译器可以在这里做这样的事情吗?

当然不是因为RecyclerViewAdapter.ViewHolderRecyclerViewAdapter 类是私有的,而这段代码是在另一个类中编写的。

【讨论】:

  • 谢谢。我想我理解你的大部分解释。当你写的时候我不明白你的意思:“所以你应该有一个公共接口,RecyclerViewAdapter.ViewHolder 实现了它”,并且还完成了它之后的部分(带有cast),是不是和界面建议有关?
  • 对于第一部分,我编辑了我的答案以使其清楚,并且铸造部分与界面无关,它与类型擦除有关。当编译器在编译时检查类型时,它将对象类型转换为确切的对象类型,当编译器编译代码时,getView() 方法的返回类型为RecyclerViewAdapter.ViewHolde,因此它将对象转换为其确切类型。而且在运行时你没有像 T 这样的东西,每个对象都被强制转换为它们的确切类型。
  • 您的示例中的RecyclerViewAdapter.ViewHolder 类实现的接口中的方法是什么?你所有的答案真的很棒,但我真的很想了解界面含义,但不幸的是还是不能
  • @Eitanos30 忘记interface 在这里提到是我的错误,它使这个答案变得复杂我刚刚编辑了我的答案,请再读一遍。
  • 好的(虽然很高兴了解界面问题:))。谢谢!
【解决方案3】:

根据Java-Spec Page -164 中的可访问性规则,声明的私有成员只能在顶级类的主体内访问。我希望类的主体不是它的定义。

** 否则,成员或构造函数被声明为私有,并且当且仅当它出现在包含成员或构造函数声明的顶级类(第 7.6 节)的主体内时才允许访问。 **

【讨论】:

  • 谢谢!对不起,我只能批准一个答案。再次感谢
猜你喜欢
  • 2021-02-28
  • 2016-06-30
  • 1970-01-01
  • 1970-01-01
  • 2022-01-25
  • 2020-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多