我本来想创建一个可以在构造函数中中止实例化的类,但是根据this link,我应该改用Factory类。但是,现在我要阻止工厂类以外的任何人创建“内部”类的对象,同时让所有人都可以访问内部类的方法。
我已经尝试过this answer。
import java.util.Date
object InnerFactory {
class Inner private constructor(startDate: Date? = null, endDate: Date? = null) {
fun getTimeDifference(): Long? {
//calculates time difference but doesn't matter to this example
}
}
fun createInnerObject(startDate: Date? = null, endDate: Date? = null): Inner? {
if (startDate != null && endDate != null && !endDate.after(startDate)) {
return null
}
return Inner(startDate, endDate)
}
}
我会像以下那样使用它:
val date1 = Date(1547600000)
val date2 = Date(1547600600)
val inner = InnerFactory.createInnerObject(date1, date2) //should return an instance
val invalidInner = InnerFactory.createInnerObject(date2, date1) //should not return an instance because the "endDate" is before "startDate"
val difference = inner?.getTimeDifference()
当将鼠标悬停在“ createInnerObject”函数中对构造函数的使用上时,它说“无法访问'
答案 0 :(得分:4)
您可以做什么:
interface Inner
,其中应包含所有应公开的功能private
并实现该接口示例:
object InnerFactory {
interface Inner {
fun getTimeDifference(): Long?
}
private class InnerImpl(startDate: Date? = null, endDate: Date? = null) : Inner {
override fun getTimeDifference(): Long? = TODO("some implementation")
}
fun createInnerObject(startDate: Date? = null, endDate: Date? = null): Inner? {
if (startDate != null && endDate != null && !endDate.after(startDate)) {
return null
}
return InnerImpl(startDate, endDate) // InnerImpl accessible from here but not from outside of InnerFactory...
}
}
现在您无法再从外部访问InnerImpl
,但仍然具有所有必需的功能:
// the following all work as it deals with the interface
val inner = InnerFactory.createInnerObject(date1, date2) //should return an instance
val invalidInner = InnerFactory.createInnerObject(date2, date1) //should not return an instance because the "endDate" is before "startDate"
val difference = inner?.getTimeDifference()
// the following will not compile:
InnerImpl()
答案 1 :(得分:2)
不幸的是,无法从外部实例访问private
内部Kotlin成员:
private
意味着仅在此类内可见
Kotlin reference / Visibility modifiers
但是,Java的可见性修饰符并不局限于此:
当且仅当访问发生在包含成员或构造函数的声明的顶级类型(§7.6)的主体内时,才允许访问。
Java Language Specification / §6 Names / §6.6 Access Control / §6.6.1 Determining Accessibility
这是我发现的仅有的(烦人的)案例之一,其中Kotlin的规则使普通的Java模式成为不可能。
唯一的解决方法(如果要保留当前结构,是 if )将是用Java重写该类,或以较少的可见性(例如internal
公开此构造函数)。 )
在Kotlin论坛上有一个关于discussion的信息-似乎这是JVM的局限性,并且仅在Java中有效,因为编译器会生成适当的synthetic
访问器。
答案 2 :(得分:0)
您可以制作constructor
protected
。这样,您仅将其公开给子类,在本例中为PrivateClass
。然后,您将创建PrivateClass
或null
的实例,但将其返回为InnerClass?
。
object InnerFactory {
fun createInnerObject(startDate: Date? = null, endDate: Date? = null): Inner? {
// return null here if conditions are not met
return PrivateClass(startDate, endDate)
}
open class Inner protected constructor(val startDate: Date?, val endDate: Date?) {
fun getTimeDifference(): Long? { /* ... */ }
}
private class PrivateClass(startDate: Date?, endDate: Date?): Inner(startDate, endDate)
}