简体   繁体   English

Kotlin 构造函数 val 与私有 val

[英]Kotlin constructor val vs private val

If I have something like the following:如果我有以下内容:

interface IRecordService {

   fun doSomething () : Record

}

@MongoRepository
interface IRecordRepository : MongoRepository<Record, String> {

}

@Service
class RecordService  (
   private val recordRepository : IRecordRepository // or just val instead of private val
) : IRecordService
{

   override fun doSomething () : Record {
      // does something
   }

}

Is there any difference between using private val in the RecordService constructor vs just val ?RecordService构造函数中使用private val与仅使用val有什么区别吗? I've seen both being used but couldn't tell if there was a recommended way or why.我已经看到两者都在使用,但不知道是否有推荐的方法或为什么。

If you put val , it will be a constructor parameter and property.如果你放val ,它将是一个构造函数参数属性。 If you don't, it will be a constructor parameter (NOT property).如果你不这样做,它将是一个构造函数参数(不是属性)。 See Why to put val or var in kotlin class constructors请参阅为什么将 val 或 var 放入 kotlin 类构造函数

This isn't specific to Spring or Mongo;这不是特定于 Spring 或 Mongo 的。 it's just core Kotlin.它只是 Kotlin 的核心。 There are several things going on here;这里发生了几件事; I'll try to unpick them.我会试着解开它们。

Consider the simpler definition:考虑更简单的定义:

class MyClass(i: Int)

The parens specify the primary constructor : any parameters there (such as i ) are passed into the class, and are available during construction.括号指定主构造函数:那里的任何参数(例如i )都被传递到类中,并且在构造期间可用。 So you could pass them up to the superclass constructor, use them in property initialisers, and/or in an init block:因此,您可以将它们传递给超类构造函数,在属性初始化器和/或init块中使用它们:

class MyClass(i: Int) : MySuperclass(i) {
    val someProperty = i

    init {
        println("i is $i")
    }
}

However, they don't persist after the instance has been constructed — so you couldn't refer to them in methods, or from outside the class.但是,它们在实例构建后不会持续存在——因此您无法在方法中或从类外部引用它们。

If you want to do that, you have to define a property for each parameter you want to persist.如果要这样做,则必须为要保留的每个参数定义一个属性 You could do that explicitly, eg:你可以明确地做到这一点,例如:

class MyClass(i: Int) {
    val i2 = i
}

Here every instance of MyClass has a property called i2 which is initialised to the i constructor parameter.这里MyClass的每个实例都有一个名为i2的属性,它被初始化为i构造函数参数。

However, because this is a common pattern, Kotlin provides a shortcut.但是,因为这是一种常见的模式,所以 Kotlin 提供了一种快捷方式。 If you specify val or var in the primary constructor:如果在主构造函数中指定valvar

class MyClass(val i: Int)

then Kotlin creates a property with the same name as the parameter, and initialises it for you.然后 Kotlin 创建一个与参数同名的属性,并为您初始化它。 So every instance of the above class has a property called i that you can refer to at any time.因此,上述类的每个实例都有一个名为i的属性,您可以随时引用它。

By default, properties in Kotlin are public : you can access them from inside the class, from subclasses, from other classes in the same module, and from any other code that has a MyClass instance.默认情况下,Kotlin 中的属性是public的:您可以从类内部、子类、同一模块中的其他类以及具有MyClass实例的任何其他代码中访问它们。

However, in some cases it's useful to restrict access, so you can add a visibility modifier : internal prevents code in other modules from seeing it, protected allows only subclasses to see it, and private makes it visible only inside the class itself.但是,在某些情况下,限制访问很有用,因此您可以添加可见性修饰符internal防止其他模块中的代码看到它, protected仅允许子类看到它,而private使其仅在类本身内部可见。

So, to answer your question: without the private modifier, any code that had access to your RecordService would be able to access its recordRepository property;所以,回答你的问题:没有private修饰符,任何可以访问RecordService的代码都可以访问它的recordRepository属性; adding private prevents that, and means that only code within RecordService can see it.添加private可以防止这种情况发生,这意味着只有RecordService中的代码才能看到它。

In general, it might be a good idea to centralise all access to the recordRepository in the one class;一般来说,将所有对recordRepository的访问集中在一个类中可能是个好主意。 then making it private would ensure that no other code can muck around with it.然后将其private将确保没有其他代码可以使用它。 That would make it easier to see what's going on, easier to debug, and safer to work on.这将更容易看到正在发生的事情,更容易调试,并且更安全地工作。 (However, we obviously don't know about the rest of your program, and can't advise on whether that would be a good plan in your case.) (但是,我们显然不了解您的程序的其余部分,并且无法就您的情况是否是一个好的计划提供建议。)


By the way, using an I prefix for interfaces is not a convention that's used much in Kotlin (or Java).顺便说一句,在接口中使用I前缀并不是 Kotlin(或 Java)中常用的约定。 There's often little point in having an interface with only one implementation;只有一个实现的接口通常没有什么意义。 and if you could have multiple implementations, then better to use a simple term for the interface and then more specific terms for the implementations.如果您可以有多个实现,那么最好使用一个简单的术语来表示接口,然后使用更具体的术语来表示实现。 (For example: the List interface with ArrayList and LinkedList classes, or Number with Int and Long .) (例如:带有ArrayListLinkedList类的List接口,或带有IntLongNumber 。)

首先如果你使用val它将这个构造函数参数转换为属性,如果你不想从其他类中隐藏这个属性(设置它),你可以使用val 。但是如果你不希望你的属性被其他类更改您应该改用private val

Well, you can use both val and private val in your constructor there's no problem in that, it's just that with private keyword your properties wont be modified or accessed by some other class, so it basically provides some data hiding.好吧,您可以在构造函数中同时使用valprivate val ,这没有问题,只是使用private关键字,您的属性不会被其他类修改或访问,因此它基本上提供了一些数据隐藏。 If you talking about difference in functionality inside your RecordService class, then no there wont be any difference.如果您谈论RecordService类中的功能差异,那么不会有任何差异。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM