Kotlin 中抽象 class 的实例并在不覆盖的情况下调用抽象函数
Instance of abstract class in Kotlin and calling abstract function without overriding
我正在做这个 google 代码实验室 android-room-with-a-view-kotlin。这是link到codelab。在创建房间数据库的第 8 步,他们使用了此代码
// Annotates class to be a Room Database with a table (entity) of the Word class
@Database(entities = arrayOf(Word::class), version = 1, exportSchema = false)
public abstract class WordRoomDatabase : RoomDatabase() {
abstract fun wordDao(): WordDao
companion object {
// Singleton prevents multiple instances of database opening at the
// same time.
@Volatile
private var INSTANCE: WordRoomDatabase? = null
fun getDatabase(context: Context): WordRoomDatabase {
// if the INSTANCE is not null, then return it,
// if it is, then create the database
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
WordRoomDatabase::class.java,
"word_database"
).build()
INSTANCE = instance
// return instance
instance
}
}
}
}
我想问一下为什么我创建这个抽象的实例 class (in class A) 然后调用的这两行 (val exam & val dao) 没有错误它的抽象 function(getNoteDao)
而不覆盖它。
class A{
val exam : WordRoomDatabase = WordRoomDatabase.getDatabase(application)
val dao = exam.getWordDao()
}
因为我们知道我们需要覆盖 abstract
function
并且不能直接调用它但是那里发生了什么。为什么没有错误
exam
行没有错误,因为 getDataBase
是一个“伴随”对象,或者如果您来自 Java 世界,则意味着它是一个“静态”对象摘要中的函数 class。这意味着
- 伴生对象中的函数(或静态函数)属于 CLASS,而不是 class
的实例
- 您不能在 class 的实例上调用 static/companion 对象函数,所以请注意当您调用“WordRoomDatabase.getDatabase...”时末尾没有括号的“WordRoomDatabase”。您不需要创建它的实例来调用
getDatabase
函数
第 2 行没有错误,这有点难以发现。
在 getDatabase()
中你是 Room.dataBaseBuilder(...)
并传入摘要 class。在该构建器内部,android 实际上创建了抽象 WordRoomDatabase
的实例。 class 并覆盖您的抽象 wordDao
函数
如果您使用的是 AndroidStudio,请构建您的代码。完成后,WordRoomDatabase
旁边的列上会出现一个向下的绿色小箭头。如果单击它,您将能够看到 Room 生成的 class 覆盖了您的抽象函数
您不会收到任何错误,因为这些抽象 classes 的实现是由 kapt
在编译时自动生成的。如果您仔细查看 build.gradle
文件,您会发现它包含一个格式为
的依赖项
kapt 'androidx.room:room-compiler:X.X.X'
这里kapt
代表kotlin注解处理工具,它处理你所有class带有某些注解如@Database
的Room或 @Dao
并生成它们的实现。例如,我定义了以下@Dao interface
@Dao
interface WordDao {
@Insert
fun insert(word: Word)
}
并且 kapt
在执行此 class
后生成
public final class WordDao_Impl implements WordDao {
private final RoomDatabase __db;
private final EntityInsertionAdapter<Word> __insertionAdapterOfWord;
public WordDao_Impl(RoomDatabase __db) {
this.__db = __db;
this.__insertionAdapterOfWord = new EntityInsertionAdapter<Word>(__db) {
@Override
public String createQuery() {
return "INSERT OR ABORT INTO `Word` (`someId`) VALUES (?)";
}
@Override
public void bind(SupportSQLiteStatement stmt, Word value) {
stmt.bindLong(1, value.getSomeId());
}
};
}
@Override
public void insert(final Word word) {
__db.assertNotSuspendingTransaction();
__db.beginTransaction();
try {
__insertionAdapterOfWord.insert(word);
__db.setTransactionSuccessful();
} finally {
__db.endTransaction();
}
}
}
WordRoomDatabase
也是如此,它的实现也是自动生成的。如果你想查看这些 classes 你总是可以在 \app\build\generated\source\kapt\debug\yourpackage
找到它们,它们标有 _Impl 后缀。
我正在做这个 google 代码实验室 android-room-with-a-view-kotlin。这是link到codelab。在创建房间数据库的第 8 步,他们使用了此代码
// Annotates class to be a Room Database with a table (entity) of the Word class
@Database(entities = arrayOf(Word::class), version = 1, exportSchema = false)
public abstract class WordRoomDatabase : RoomDatabase() {
abstract fun wordDao(): WordDao
companion object {
// Singleton prevents multiple instances of database opening at the
// same time.
@Volatile
private var INSTANCE: WordRoomDatabase? = null
fun getDatabase(context: Context): WordRoomDatabase {
// if the INSTANCE is not null, then return it,
// if it is, then create the database
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
WordRoomDatabase::class.java,
"word_database"
).build()
INSTANCE = instance
// return instance
instance
}
}
}
}
我想问一下为什么我创建这个抽象的实例 class (in class A) 然后调用的这两行 (val exam & val dao) 没有错误它的抽象 function(getNoteDao)
而不覆盖它。
class A{
val exam : WordRoomDatabase = WordRoomDatabase.getDatabase(application)
val dao = exam.getWordDao()
}
因为我们知道我们需要覆盖 abstract
function
并且不能直接调用它但是那里发生了什么。为什么没有错误
exam
行没有错误,因为 getDataBase
是一个“伴随”对象,或者如果您来自 Java 世界,则意味着它是一个“静态”对象摘要中的函数 class。这意味着
- 伴生对象中的函数(或静态函数)属于 CLASS,而不是 class 的实例
- 您不能在 class 的实例上调用 static/companion 对象函数,所以请注意当您调用“WordRoomDatabase.getDatabase...”时末尾没有括号的“WordRoomDatabase”。您不需要创建它的实例来调用
getDatabase
函数
第 2 行没有错误,这有点难以发现。
在 getDatabase()
中你是 Room.dataBaseBuilder(...)
并传入摘要 class。在该构建器内部,android 实际上创建了抽象 WordRoomDatabase
的实例。 class 并覆盖您的抽象 wordDao
函数
如果您使用的是 AndroidStudio,请构建您的代码。完成后,WordRoomDatabase
旁边的列上会出现一个向下的绿色小箭头。如果单击它,您将能够看到 Room 生成的 class 覆盖了您的抽象函数
您不会收到任何错误,因为这些抽象 classes 的实现是由 kapt
在编译时自动生成的。如果您仔细查看 build.gradle
文件,您会发现它包含一个格式为
kapt 'androidx.room:room-compiler:X.X.X'
这里kapt
代表kotlin注解处理工具,它处理你所有class带有某些注解如@Database
的Room或 @Dao
并生成它们的实现。例如,我定义了以下@Dao interface
@Dao
interface WordDao {
@Insert
fun insert(word: Word)
}
并且 kapt
在执行此 class
public final class WordDao_Impl implements WordDao {
private final RoomDatabase __db;
private final EntityInsertionAdapter<Word> __insertionAdapterOfWord;
public WordDao_Impl(RoomDatabase __db) {
this.__db = __db;
this.__insertionAdapterOfWord = new EntityInsertionAdapter<Word>(__db) {
@Override
public String createQuery() {
return "INSERT OR ABORT INTO `Word` (`someId`) VALUES (?)";
}
@Override
public void bind(SupportSQLiteStatement stmt, Word value) {
stmt.bindLong(1, value.getSomeId());
}
};
}
@Override
public void insert(final Word word) {
__db.assertNotSuspendingTransaction();
__db.beginTransaction();
try {
__insertionAdapterOfWord.insert(word);
__db.setTransactionSuccessful();
} finally {
__db.endTransaction();
}
}
}
WordRoomDatabase
也是如此,它的实现也是自动生成的。如果你想查看这些 classes 你总是可以在 \app\build\generated\source\kapt\debug\yourpackage
找到它们,它们标有 _Impl 后缀。