如何在内部类中定义常量?

Posted

技术标签:

【中文标题】如何在内部类中定义常量?【英文标题】:How do I define constants in an inner class? 【发布时间】:2020-01-15 06:05:01 【问题描述】:

我有以下 Java 代码,我想将其转换为 Kotlin:

class RideHistoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> 
    class HistoryItemHolder extends RecyclerView.ViewHolder 
        private static final int TYPE_IN_PROGRESS = 1
        private static final int TYPE_CANCELLED = 2
        private static final int TYPE_FINISHED = 3

        // class methods and properties are written
    

我想出了以下代码:

class RideHistoryAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() 

    private inner class HistoryItemHolder(view: View)
        : RecyclerView.ViewHolder(view) 
        private companion object 
            private const val TYPE_IN_PROGRESS = 1
            private const val TYPE_CANCELLED = 2
            private const val TYPE_FINISHED = 3

            // class methods and properties are written
        

    


android Studio 在companion object 行的“对象”下方显示红色波浪线,表示:

此处不允许伴随对象

注意:我知道我可以将其转换为非内部类,但我更愿意保留它。我还检查了我也不能在内部类中定义接口。

【问题讨论】:

您有什么特别的理由要使用内部类吗? @NatigBabayev 避免显式传递适配器的属性(内部类减少了额外的调用和值的维护)。 那为什么不把伴生对象移到父类呢? @NatigBabayev 是的,我可以这样做,但由于它与 HistoryItemHolder(内部类)而不是 RecyclerVIew(父级)有关,因此设计上是错误的。 【参考方案1】:

首先你的 Java 是无效的。如果你修复它,你会得到一个错误:Inner classes can not have static declarations

您不能在内部类中拥有伴随对象,原因与您不能拥有 static members in an inner class in java 的原因相同

https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html:

与实例方法和变量一样,内部类是关联的 具有其封闭类的实例并可以直接访问该类 对象的方法和字段。 另外,因为内部类是 与实例关联,它本身不能定义任何静态成员。

(由我突出显示)

出于同样的原因,将准静态伴随对象与实例关联是没有意义的。

解决方案(选择一个):

    使用val(类似于final)。 将伴随对象移动到封闭类。 使HistoryItemHolder 不是内部类。

【讨论】:

谢谢。我意识到我的错误。我一定写过public static final int TYPE_IN_PROGRESS = 1;。现在这是一个有效的 Java 代码。 我尝试了您的解决方案,但它没有转换 public static final 行的 Java 代码 (using this answer),而是转换为 private final(没有静态意味着它绑定到类的实例而不是课程,因此不是一个好习惯)。 如果你想拥有它static final(在伴随对象中相当于const)你必须将伴随对象移动到外部类,原因在我的回答中给出。旁注:我认为private final 字段是一个很好的解决方案。从语义上讲,它的含义非常清楚。 是的,它会起作用,但不是一个优雅的解决方案 (here's why)。使类非内部(如@NatigBabayev 所建议)似乎是该问题的唯一有效解决方案。我想我达到了 Kotlin 的罕见极限。 好点,这是解决问题的第三种方法。我会把它添加到我的答案中。【参考方案2】:

我可以确认无法在内部类中添加常量(请参阅 Kotlin 论坛上的 my question)。

但是,有两种方法可以选择(我选择了第一种):

    使ViewHolder成为一个非内部类——这意味着它不能再访问适配器的方法/属性:

    public class Adapter 
    
        public class ViewHolder(private val adapter: Adapter) 
    
            private companion object 
                private const val TYPE_IN_PROGRESS = 1
                private const val TYPE_CANCELLED = 2
                private const val TYPE_FINISHED = 3
            
        
    
    

    在适配器中定义常量:

    public class Adapter 
        private const val TYPE_IN_PROGRESS = 1
        private const val TYPE_CANCELLED = 2
        private const val TYPE_FINISHED = 3
    
        public class ViewHolder(private val adapter: Adapter) 
            // ..
        
    
    

注意:不要将您的 const val 转换为 val,因为它会将其绑定到您的类实例(这很糟糕。More about it here)。

【讨论】:

这里的第二种方式只是工作,因为适配器不是内部类,你应该得到编译错误Const 'val' are only allowed on top level or in objects @BabyishTank 绝对。这就是为什么我在回答的开头写了“不可能在内部类中添加常量”。

以上是关于如何在内部类中定义常量?的主要内容,如果未能解决你的问题,请参考以下文章

内部类

局部内部类和成员内部类

局部内部类详解

在内部类中执行main方法[重复]

---内部类-----

内部类