kotlin学习第二篇文章!直接开始!
历史文章
[AS3.6.1]Kotlin学习笔记1
上篇我们讲到类的使用JavaC.class
和KotlinC.kt
继续扩展,首先我们讲的是初始化代码块,java和kotlin的不同!不太懂可以看下这篇文章Java初始化块(静态代码块和非静态代码块)
public class JavaC {
private String name = "JavaC";
private List strs;
{
strs = new ArrayList<>();
strs.add("a");
strs.add("b");
strs.add("c");
}
public JavaC() {
}
public JavaC(String name) {
this.name = name;
}
public String getName() {
return name + ".class";
}
public void setName(String name) {
this.name = "set " + name;
}
public void logList(){
for (String str : strs) {
Log.e(name, str);
}
}
}
class KotlinC {
var name: String = "KotlinC"
//由于kotlin使用的是field代表变量所以必须直接写在变量下方
get() {
return field + ".kt"
}
set(value) {
field = "set " + value
}
var strs: Array? = null
init {
strs = arrayOf("a", "b", "c")
}
constructor()
constructor(name: String) {
this.name = name
}
fun logList(){
for (str in strs!!){
println(str)
}
}
}
还是原来的代码,就是新增了一个代码块!java中直接使用{}
就可以了而在kotlin中需要加入标示init{}
来实现,直接实例化两个方法调用
javaC.logList() // a b c
println("-------------")
kotlinC.logList() // a b c
都是同样的结果。这边再次回顾了下!!
的用法!你可以这么认为加上!!
的标示就是让kotlin的Null安全取消。
在java中我们设置一些常量的时候基本都是使用static final
但是在kotlin中没有了静态变量和静态方法,新的实现如下
//java
public static final String CONSTANT = "JavaC常量";
//kotlin
companion object{
const val CONSTANT:String = "KotlinC常量"
}
//调用
println(JavaC.CONSTANT) //JavaC常量
println(KotlinC.CONSTANT) //KotlinC常量
我们发现kotlin中完全就变了,使用了companion
object
const
一堆的关键字修饰一个常量。
上述一堆关键字我们就从object
开始讲解。在java中我们有Object
代表一切类的基类,但是在kotlin中Object
变成了Any
,而object
是一个关键字,代表了对象的意思。
我们是可以直接创建一个对象的,即对象类
object Object {
val name = "我是一个对象"
fun log(){
println(name)
}
}
我们发现直接可以看到创建类的class
直接被替换成了object
也可以直接调用
println(Object.name) //我是一个对象
Object.log() //我是一个对象
这边我们还需要了解到kotlin的object
其实是一个自带实现饿汉式单例的单例对象
我们来比对下java和kotlin的饿汉式单列代码
//java
public class JHungry {
private static final JHungry hungry = new JHungry();
private String name = "Java Hungry";
public static JHungry getInstance() {
return hungry;
}
private JHungry() {
}
public String getName() {
return name;
}
}
//kotlin
object KHungry {
var name: String = "Kotlin Hungry";
}
//调用
println(JHungry.getInstance().name) //Java Hungry
println(KHungry.name) //Kotlin Hungry
我们很明显的可以看到使用kotlin的object
对象直接生成的饿汉式的单例比java简便了非常的多!
并且object
是可以直接继承class
和interface
的能让继承的类既有 class 关键字的功能,又实现了单例。快捷且方便!
java中我们也会经常用到匿名类,kotlin中也可以实现,下面我们看下代码区别
//java
View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
//override
}
};
//Convert to lambda
View.OnClickListener listener2 = v ->{
//override
};
//kotlin
val listener = object: View.OnClickListener {
override fun onClick(v: View?) {
//override
}
}
//Convert to lambda
val listener2 = View.OnClickListener {
//override
}
可以看到由于kotlin没有new
这个关键字所以使用了object
来替代,转化成lambda的时候java省略了new
kotlin就省略打了object
经过上面object
的说明我们了解到只要用了object
生成的对象类就一定使整个类都变成了静态的,如果我们只想要部分代码静态就需要用到companion
代码就是我们一开始常量目录下的JavaC类和KotlinC类
//java
public class JavaC {
private String name = "JavaC";
public static final String CONSTANT = "JavaC常量";
//...省略其他代码
}
//kotlin
class KotlinC {
var name: String = "KotlinC"
companion object Const{
const val CONSTANT:String = "KotlinC常量"
}
//...省略其他代码
}
我们就可以这么理解companion
:可以理解为伴随、伴生,表示修饰的对象和外部类绑定。
这边我们为companion object
设置了一个名字Const
但是我们调用的代码是可以跳过object
对象的名称直接调用的
println(JavaC.CONSTANT) //JavaC常量
println(KotlinC.CONSTANT) //KotlinC常量
所以就有了常量目录下最开始的直接写法
companion object{
const val CONSTANT:String = "KotlinC常量"
}
kotlin中的top-level property
顶层声明 这可以直接去调用一个kt文件里面的方法,只需要导入包名就可以使用,非常的方便。
首先我们创建一个expand.kt文件
package com.gjn.kotlindemo
fun funExpand(){
println("fun Expand")
}
里面就一个方法,那么我们在同级目录下的其他类中可以完美的直接使用,不在同级只需要导入包名也是可以直接使用的
package com.gjn.kotlindemo
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
funExpand() //fun Expand
}
}
在java中我们经常会写一些工具类,在kotlin中就可以使用top-level property
完美简化工具类的调用,还有就是我们先在经常直接使用的println
方法我们会发现明明我们什么都都没导入直接就可以使用系统的System.out.println
了,其实你点进println
就可以看到其实是官方写了一个kt方法来实现的。
object
、companion object
和 top-level
情况那在实际使用中,在
object
、companion object
和top-level
中该选择哪一个呢?
简单来说按照下面这两个原则判断:
如果想写工具类的功能,直接创建文件,写 top-level「顶层」函数。
如果需要继承别的类或者实现接口,就用 object 或 companion object。
与java的常量有区别,kotlin的常量是有规则的
object
(包括伴生对象companion object
)或者「top-level
顶层」中,因为常量是静态的。const
关键字。String
类型可以声明成常量。这边kotlin和java有一点很大的区别,就是不能把非基本类型设置成常量。这是因为kotlin中的常量就是代表了在编译之后百分百不会变动的才是常量,而很多非基本类都是设置一个伪常量对象,实际运行中是会被修改内部的属性的,所以属于伪常量。
我这边觉一个例子,我们在app运行前并没有获取服务器部分数据,拿到json数据之后转换成常量对象,所以我们会先设置一个常量对象设置null当服务器获取数据之后在来配置一些基本值。这个时候
我们开始设置的常量对象其实就只是一个伪常量因为我们获取到数据之后其实改变了常量对象内的值,所以在kotlin中直接就去掉这个概念,防止一些错误产生。
第一篇中讲for的调用的时候,稍微写了些数组和集合。下面我们来正式讲一下kotlin的数组和集合
首先我们看下java和kotlin创建数组的区别
//java
private String[] arrayStrs = {"java1", "java2", "java3"};
//kotlin
val arrayStrs: Array = arrayOf("kotlin1", "kotlin2", "kotlin3")
我们可以看到kotlin中的数组其实是一个对象是可以直接调用一些常用的方法的,为了更加便捷。
取值和修改和java中是一样的
println(kotlinC.arrayStrs[1]) //kotlin2
kotlinC.arrayStrs[0] = "test"
println(kotlinC.arrayStrs[0]) //test
kotlin和java一样有三种集合类型:List、Set 和 Map。
和创建数组一样集合也是可以快速创建的
//java
private List strList = new ArrayList<>();
strList.add("a");
strList.add("b");
strList.add("c");
strList.add("b");
strList.add("a");
private Set strSet = new HashSet<>();
strSet.add("a");
strSet.add("b");
strSet.add("c");
strSet.add("b");
strSet.add("a");
private Map strMap = new HashMap<>();
strMap.put(1, "a");
strMap.put(2, "b");
strMap.put(3, "c");
strMap.put(4, "b");
strMap.put(5, "a");
//kotlin
val strList = listOf("a", "b" , "c", "b" , "a")
val strSet = setOf("a", "b" , "c", "b" , "a")
val strMap = mapOf(1 to "a", 2 to "b", 3 to "c", 4 to "b", 5 to "a")
我们能够看到,kotlin创建数组添加数据比java方便了许多。
这边要注意一下使用listOf
setOf
mapOf
生成的集合是只读集合,是无法修改值的。想要修改值可以使用toMutableList
toMutableSet
toMutableMap
方法或者直接创建一个mutableListOf
mutableSetOf
mutableMapOf
集合,可以发现可变的集合都是使用mutable
前缀修饰
这是kotlin引入的新容器。它和Iterable
一样用来遍历一组数据并可以对每个元素进行特定的处理。
基本使用如下
val strSeq =sequenceOf("a", "b", "c", "b", "a")
//strList是上面创建的 基本上最常用的创建方法
val strSeq2 = strList.asSequence()
//generateSequence按方法推断生成 直到返回结果为null
//无限序列
val strSeq3 = generateSequence(0){ it + 1}
//有限序列
val strSeq4 = generateSequence(0){
if (it < 10){
it + 1
}else{
null
}
}
那么问题来了,这个有啥用呢?我们可以把序列简单理解为Java8中的流,序列简单一点说就是实现对集合的操作进行延迟,专业的说法叫惰性集合操作,就是把你对集合的一系列操作拖到最后一刻才执行。序列和集合的区别就是惰性求值
和及早求值
的区别,集合会在每次形式新的集合的时候全部遍历一遍,而序列是执行完后续步骤之后才会走下一个元素,不是很明白可以看下Kotlin系列之序列
public
:公开,哪都可以引用private
:私有,声明类或者文件内引用protected
:保护,在kotlin中可以理解为private
+子类引用internal
:内部,kotlin新增加的修饰符,仅在module内引用这边我们说下 private
和internal
。
首先private
和java中有点区别,就是private
的范围更小,在一个外部类新增一个内部类,如果对内部类的参数或者函数设置了private
,那么在外部类也无法直接访问或者调用内部类的参数和函数,这是和java的区别。
然后是internal
,这是kotlin新加的修饰符,可以理解为项目内可用,比如我们写一个某个工具library这个时候里面加入internal
的函数就只能在library内使用,我们外部导入这个工具library是无法调用设置internal
的函数或者参数的。
Kotlin 里那些「不是那么写的」
Java初始化块(静态代码块和非静态代码块)
Kotlin系列之序列