第四章(类、对象和接口)

Kotlin的类和接口与Java的类和接口还是有一点区别的。例如:接口可以包含属性声明。与Java不同,Kotlin的声明默认是 final?和 public?的。此外,嵌套的类默认并不是内部类:它们并没有包含对其外部类的隐式引用。

Kotlin中的接口

Kotlin的接口与Java 8中的相似:它们可以包含抽象方法的定义以及非抽象方法的实现。与Java 8不同的是,Java 8中需要你在这样的实现上标注default关键字,而Kotlin没有特殊的注解:只需要提供一个方法体。示例:

interface Clickable {
    fun click()
    fun showOff() { //带默认方法的实现
        println("Clickable!")
    }
}

上面是接口的基本定义方式,接下来我们了解下如何实现接口?Kotlin在类名后面使用冒号来代替了Java中的extends和implements关键字。和Java一样,一个类可以实现任意多个接口,但是只能继承一个类。与Java中的 @Override?注解类似,Kotlin中使用 override?修饰符来标注被重写的父类或者接口的方法属性。与Java不同的是,在Kotlin中使用 override?修饰符是强制要求的。?

open class TextView : Clickable {

    override fun click() {
        // 此方法必须实现
    }

//    override fun showOff() { //接口有默认实现,这里可以不用再实现此方法
//        super.showOff()
//    }

}

class Button : TextView() {
    // 需要注意的是,Kotlin中继承与实现接口都是用的冒号,区别在于继承类时,
    //如果父类有主构造方法,则需要在类名后添加括号及主构造函数中的参数,如果没有主构造方法,
    //则必须加上一个默认的空括号来表示。
    //如上面的TextView(),而继承接口只需要直接写接口名称即可。关于主构造函数下面有说
}

那么如果我们还有一个接口Focusable,该接口下有一个和Clickable接口中的showOff一样的方法,当TextView同时继承这两个接口的时候,到底该如何实现这两个方法呢?

open class TextView : Clickable,Focusable {

  /**
  * 如果同样的继承成员有不止一个实现,那么必须最少提供一个显示实现
  * 即super<Clickable>.showOff()
        super<Focusable>.showOff()两行中最少要调用其中一行
  */
    override fun showOff() {
      // 通过下面代码显示的实现两个showOff方法
        super<Clickable>.showOff()
        super<Focusable>.showOff()
    }

    override fun click() {
        // 此方法必须实现
    }
}

修饰符

open

Java中允许你创建任意类的子类并重写任意方法,除非显示地使用了 final?关键字进行标注。而在Kotlin中,默认都是 final?的,也就是默认都是不能被继承或者重写的。如果你想允许创建一个类的子类,则需要使用 open?修饰符来标识这个类。此外,需要给每一个可以被重写的属性或方法添加 open?修饰符。

注意:如果你重写了一个基类或者接口的成员,重写了的成员同样默认是open的。如果你想改变这一行为,阻止你的类的子类重写你的实现,可以显示地将重写的成员标注为 final?。

open class RichButton:Clickable{ //这个类是open的,其他类可以继承它
    override fun click() {//这个函数重写了一个open函数并且它本身也是oepn的

    }
    fun disable(){} //这个函数是final的:不能在子类中重写它

    open fun animate(){} //这个函数是open的,可以在子类中重写它
}

abstract

在Kotlin中,同Java一样,可以将一个一个类声明为 abstract?的,这种类不能被实例化。一个抽象类通常包含一些没有实现并且必须在子类重写的抽象成员。抽象成员始终是open的,所以不需要显示地使用open修饰符。

abstract class Animated{ //这个类是抽象的:不能创建它的实例
    abstract fun animate()//这个函数是抽象的:他没有实现,必须被子类重写

    open fun stopAnimating(){ //抽象类中的非抽象函数并不是默认open的,但是可以标注为open的

    }

    fun animateTwice(){ // 不是open的,不能被重写

    }
}

类中访问修饰符的意义

修饰符 相关成员 评注
final 不能被重写 类中成员默认使用
open 可以被重写 需要明确的表明
abstract 必须被重写 只能在抽象类中使用;抽象成员不能有实现
override 重写父类或者接口中的成员 如果没有使用final表明,重写的成员默认是open的

可见性修饰符(public等)

Kotlin中的可见性修饰符与Java中的类似。同样可以使用public、protected和private修饰符。但是默认的可见性是不一样的:如果省略了修饰符,声明默认就是public的。
Java中的默认可见性——包私有,在Kotlin中并没有使用。Kotlin只把包作为在命名空间里组织代码的一种方式使用,并没有将其用作可见性控制。
作为替代方案,Kotlin提供了一个新的修饰符,internal?,表示“只在模块内部可见”。一个模块就是一组一起编译的Kotlin文件。这有可能是一个Intellij?IDEA模块、一个Eclipse项目、一个Maven或Gradle项目或者一组使用调用Ant任务进行编译的文件。

Kotlin的可见性修饰符

修饰符 类成员 顶层声明
pulbic(默认) 所有地方可见 所有地方可见
internal 模块中可见 模块中可见
protected 子类中可见 没有protected修饰符
private 类中可见 文件中可见

示例:下面giveSpeech函数的每一行都试图违反可见性规则。在编译时就会发生错误。

 internal open class TalkativeButton:Focusable{
        private fun yell() = println("Hey!")
        protected  fun whisper() = println("talk")
    }

 fun TalkativeButton.giveSpeech(){ //错误:"public"成员暴露了其"internal"接收者类型TalkativeButton
      yell() //错误:不能访问"yell()":它在"TalkativeButton"中是"private"的
     whisper() //错误:不能访问"whisper()":它在"TalkativeButton"中是"protected"的
  }

要解决上面例子中的问题,既可以把giveSpeech函数改为internal的,也可以把类改成public的,当然,如果要访问“yell与whisper方法,则需要将这两个方法改为public或者internal的。

内部类和嵌套类

和Java一样,在Kotlin中可以在另一个类中声明一个类。区别是Kotlin的嵌套类不能访问外部类的实例,除非你特别的做出了要求。
在Kotlin中,没有显示修饰符的嵌套类与Java中的static嵌套类时一样的。要把它变成一个内部类来持有一个外部类的引用的话需要使用 inner?修饰符。在Kotlin中引用外部类示例的语法也与Java不同。需要使用[email protected]从InnerClass去访问Outerclass类。

嵌套类和内部类在Java与Kotlin中的对应关系

类A在另一个类B中声明 在Java中 在Kotlin中
嵌套类(不存储外部类的引用) static?class?A class?A
内部类(存储外部类的引用) class?A inner?class?A

sealed密封类:定义受限的继承结构

当使用when结构来执行表达式的时候,Kotlin编译器会强制检查默认选项。例如:假设父类Expr有两个子类:表示数字的Num,以及表示两个两个表达式之和的SUm。在when表达式中处理所有可能的子类固然很方便,但是必须提供一个else分支来处理没有任何其他分支能匹配的情况:

interface Expr

class Num(val value:Int):Expr
class Sum(val left:Expr,val right:Expr):Expr

fun eval(e:Expr):Int = when(e){
    is Num -> e.value
    is Sum -> eval(e.right)+ eval(e.left)
    else -> throw IllegalArgumentException("Unknown expression")
}

上面示例中,else条件中因为不能返回一个有意义的值,所以直接抛出了一个异常。如果你添加了一个新的子类,编译器并不能发现有地方改变了。如果你忘记了添加一个新分支,就会选择默认的else分支,这有可能导致潜在的bug。
Kotlin为这个问题提供了一个解决方案:sealed类。为父类添加一个sealed修饰符,对可能创建的子类做出严格的限制。所有的直接子类必须嵌套在父类中。

sealed class Expr{
    class Num(val value:Int):Expr()
    class Sum(val left:Expr,val right:Expr):Expr()
}

fun eval(e:Expr):Int = when(e){
    is Expr.Num -> e.value
    is Expr.Sum -> eval(e.right)+ eval(e.left)
}

如果你在when表达式中处理所有sealed类的子类,你就不再不要提供默认的分支。注意,sealed修饰符隐含的这个类是一个open类,你不再需要显示地添加open修饰符。当你sealed类(Expr)的子类中添加一个新的子类的时候,有返回值的when表达式会编译失败。需要将新的子类添加一个新分支。

声明构造方法

Java中一个类可以声明一个或多个构造方法。Kotlin也是类似的,知识做出了一点修改:区分了主构造方法(通常是主要而简洁的初始化类的方法,并且在类体外部声明)和从构造方法(在类体内部声明)。

主构造方法

主构造方法通常直接在声明类的时候在类名后面加括号,然后在括号内声明相应的参数来进行声明,而被括号围起来的语句块就叫做主构造方法。代码如下:

//以下代码即表示声明了一个带有nickname参数的主构造方法
class User(val nickname: String)

上面代码是声明一个主构造方法的最简单的方式,但是其实上面代码Kotlin最终会帮我们进行处理,我们看下它是怎样工作的:

class User constructor(_nickname: String) {
    val nickname: String

    init {
        nickname = _nickname
    }
}

在上面例子中,出现了 constructor?和 init?两个新的关键字。constructor关键字用来开始一个主构造方法或者从构造方法的声明。init关键字用来引入一个初始化语句块。因为主构造方法有语法限制,不能包含初始化代码,这就是为什么要使用初始化语句块的原因。如果你原因,也可以在一个类中声明多个初始化语句块。

当然,如果像上面代码中初始化语句块中仅仅只是一个赋值操作,那么我们可以不需要把?nickname = _nickname这行赋值操作的代码放在初始化语句块中,因为它可以与nickname属性的声明结合。如果主构造方法没有注解或可见性修饰符,同样可以把constructor关键字省略。最终代码可以简化成如下:

class User constructor(_nickname: String) {
  val nickname = _nickname
}

以上三种主构造方法声明方式都是一样的,只不过第一种使用了最简洁的语法。

主构造方法可以像函数参数一样为构造方法参数声明一个默认值:

class User(val nickname:String = "xiaochao",val isSubscribed:Boolean = true)

fun main(args: Array<String>) {
    val user1 = User("hello")
    val user2 = User(isSubscribed = false)
    val user3 = User("kotlin",false)
}

如果你的类具有一个父类,主构造方法同样需要初始化父类:

open class User(val nickname: String)

class MyUser(nickname:String) :User(nickname){
    //...
}

如果没有给一个类声明任何构造方法,将会生成一个不做任何事的默认构造方法,如果有子类继承了该类,那么子类必须显示地调用该类的默认构造方法,即使它没有任何的参数 :

open class Button

class RadioButton: Button() {
    //...
}

如果你想要确保你的类不被其他代码实例化,则必须把构造方法标记为 private?:

class User private constructor(val name:String){
    //...
}

从构造方法

上面我们说了当一个类没有定义任何构造方法的时候,Kotlin会自动为其生成一个默认的主构造方法,所以在子类继承该类时也总是需要显示的调用父类的默认构造方法。而如果当一个类中定义了从构造方法,而没有定义主构造方法的时候,那么Kotlin不会在自动为其生成默认的主构造方法。当子类继承的时候则需要显示的调用父类的从构造方法。代码如下:

open class User{
    constructor(userName:String){
        //...
    }
    constructor(userName: String,age:Int){
        //...
    }
}

class MyUser:User{
    constructor(userName:String):super(userName) // 调用父类的从构造方法
    constructor(userName: String,age:Int):super(userName,age) // 调用父类的从构造方法
}

//当然,这里也可以像之前一样通过在继承的时候就显示调用父类的从构造方法,如下
//class MyUser(userName: String) : User(userName) {
//
//}

从上面我们看到可以在子类内部通过使用super()关键字调用对应的父类的构造方法。同时,也可以像Java中一样,通过使用this()关键字,从一个构造方法中调用你自己类的另一个构造方法。代码如下:

class MyUser : User {
    //通过this调用自己的两个参数的构造方法
    constructor(userName: String) : this(userName, 0)

    constructor(userName: String, age: Int) : super(userName, age)
}

通过getter或setter访问支持字段(field)

class User(val name:String){
    var address: String = "unspecified"
        set(value) {
            println("$field --->${value.trimIndent()}")
            field = value
        }
}

fun main(args: Array<String>) {
    val user = User("xiaochao")
    user.address = "shanghai"
    user.address = "beijing"
}
>>> unspecified --->shanghai
>>> shanghai --->beijing

上面代码实现了一个既可以存储值又可以在值被访问和修改时提供额外逻辑的属性。要支持这种情况,需要能够从属性的访问器中访问它的支持字段(field)。在setter的函数体中,使用了特殊的标识符field来访问支持字段的值。在getter中,只能读取值;而在setter中,既能读取它也能修改它。

有支持字段的属性和没有的有什么区别?
访问属性的方式不依赖于它是否含有支持字段。如果你显示地引用或者使用默认的访问器实现,编译器会为属性生成支持字段。如果你提供了一个自定义的访问器实现并且没有使用 field?,支持字段将不会被呈现出来。

有时候不需要修改访问器的默认实现,但是需要修改它的可见性。则代码示例如下:

class LengthCounter {
    var counter: Int = 0
        private set

    fun addWord(word: String) {
        counter += word.length
    }
}

fun main(args: Array<String>) {
    val lengthCounter = LengthCounter()
    lengthCounter.addWord("HelloWorld!")
    println(lengthCounter.counter)
}

>>> 11

数据类data

数据类用 data?关键字修饰,数据类表示已经被Kotlin重写了equal、hashCode、toString方法的类。示例如下:

class Student(val name:String,val age:Int)

data class DataStudent(val name:String ,val age:Int)

fun main(args: Array<String>) {
    val xiaoming1 = Student("xiaoming",20)
    val xiaoming2 = Student("xiaoming",20)
    val xiaomingSet = hashSetOf(xiaoming1,xiaoming2)
    println(xiaoming1.toString())
    println(xiaoming1==xiaoming2)
    println("size = ${xiaomingSet.size} ${xiaomingSet.contains(Student("xiaoming",20))}")
    println("----------------------------")

    val dataxiaoming1 = DataStudent("xiaoming",20)
    val dataxiaoming2 = DataStudent("xiaoming",20)
    val dataxiaomingSet = hashSetOf(dataxiaoming1,dataxiaoming2)
    println(dataxiaoming1.toString())
    println(dataxiaoming1==dataxiaoming2)
    println("size = ${dataxiaomingSet.size} ${dataxiaomingSet.contains(DataStudent("xiaoming",20))}")
}

>>>[email protected]
>>>false
>>>size = 2 false
>>>----------------------------
>>>DataStudent(name=xiaoming, age=20)
>>>true
>>>size = 1 true

数据类和不可变性:copy()方法

虽然数据类的属性并没有要求一定是val —?同样可以使用var —?但还是强烈推荐只使用val属性,让数据类的示例不可变。如果你想使用这样的示例作为HashMap或者类似容器的键,这会是必须的要求,因为如果不这样,被用作键的对象在加入容器后被修改了,容器可能会进入一种无效的状态。不可变对象同样更容易理解,特别是在多线程中:一旦一个对象被创建出来,它会一直保持初始状态,也不用担心在你的代码工作时其他线程修改了对象的值。

为了让使用不可变对象的数据类变得更容易,Kotlin编译器为它们多生成了一个方法:一个允许copy类的实例的方法,并在copy的同时修改了某些属性的值。创建副本通常是修改实例的好选择:副本有着单独的生命周期而且不会影响代码中引用原始实例的位置。下面就是手动实现copy方法后看起来的样子:

class Student(val name:String,val age:Int){
    fun copy(name:String = this.name,age:Int = this.age) = Student(name,age)
}

fun main(args: Array<String>) {
    val student = Student("xiaoming",22)
    println(student.copy(age = 23).age)
}
>>> 23

这就是data修饰符是如何让值对象类的使用更方便的原因。

类委托:by关键字

在开发中,我们可能常常需要向其他类添加一些行为,即使它并没有被设计为可扩展的。一个常用的实现方式以装饰器模式闻名。这种模式的本质就是创建一个新类,实现与原始类一样的接口并将原来的类的实例作为一个字段保存。与原始类拥有同样行为的方法不用被修改,只需要直接转发到原始类的实例。

这种方式的一个缺点是需要相当多的样板代码。例如,下面就是你需要多少代码来实现一个简单得如Collection的接口的装饰起,即使你不需要修改任何的行为:

class DelegatingCollection<T> : Collection<T> {
    private val innerList = arrayListOf<T>()
    override val size: Int
        get() = innerList.size

    override fun contains(element: T): Boolean = innerList.contains(element)

    override fun containsAll(elements: Collection<T>): Boolean = innerList.containsAll(elements)

    override fun isEmpty(): Boolean = innerList.isEmpty()

    override fun iterator(): Iterator<T> = innerList.iterator()
}

Kotlin中将委托作为一个语言级别的功能做了头等支持,无论什么时候实现一个接口,你都可以使用 by?关键字将接口的实现委托到另一个对象。下面通过使用by关键字来实现上面同样功能代码:

class DelegatingCollection<T>(innerList: Collection<T> = ArrayList<T>())
    : Collection<T> by innerList

现在,当你需要修改某些方法的行为时,你可以重写它们,这样你的方法就会被调用而不是使用生成的方法。可以保留感到满意的委托给内部的实例中的默认实现。

class CountingSet<T>(val innerList: MutableCollection<T> = HashSet<T>()) : MutableCollection<T> by innerList {
    var objectsAdd = 0
    override fun add(element: T): Boolean {
        objectsAdd++
        return innerList.add(element)
    }

    override fun addAll(elements: Collection<T>): Boolean {
        objectsAdd += elements.size
        return innerList.addAll(elements)
    }
}

fun main(args: Array<String>) {
    val cset = CountingSet<Int>()
    cset.addAll(listOf(1, 2, 2))
    println("${cset.objectsAdd}     ${cset.size}")
}

>>> 3     2

object:将声明一个类与创建一个实例结合

object?关键字使用主要有三种场景:

  • 定义单例
  • 替代Java的匿名内部类
  • 配合companion创建伴生对象

对象声明:通过object创建单例

object SingleInstance {
    var name: String? = null
    fun initName() {
        name = "hello world"
    }
}

fun main(args: Array<String>) {
    val a = SingleInstance
    val b = SingleInstance
    SingleInstance.initName()
    b.initName()
    println(a === b)
}
>>> true

与类一样,一个对象声明也可以包含属性、方法、初始化语句块等的声明。唯一不允许的就是构造方法(包括主构造方法和从构造方法)。与普通的实例不同,对象声明在定义的时候就立即创建了。对象声明同样可以继承自类和接口。

用object替代Java的匿名内部类

interface Click{
    fun onClick()
    fun onLongClick()
}

fun main(args: Array<String>) {
    val clickClistener = object :Click{
        override fun onClick() {
        }

        override fun onLongClick() {
        }
    }
}

当使用object来表示匿名内部类时,与对象声明不同,匿名对象不是单例的,每次对象表达式被执行都会创建一个新的对象实例。

伴生对象

Kotlin中的类不能拥有静态成员;Java中的static关键字并不是Kotlin语言的一部分。作为替代,Kotlin依赖包级别函数和对象声明,在大多数情况下,还是推荐使用顶层函数,但是顶层函数不能访问类的private成员。这时候就可以考虑通过伴生对象来解决这个问题。在Kotlin中,伴生对象通过 companion?来标记。语法如下:

class A {
    companion object {
        const val name = "Hello world"
        fun bar() {
            println("Companion object called")
        }
    }
}

fun main(args: Array<String>) {
    A.bar()
    A.name
}

伴生对象是一个声明在类中的普通对象,它可以有名字,实现一个接口或者有扩展函数或属性。

interface Click{
        fun onClick()
    fun onLongClick()
}

class A {
    companion object Inner : Click { // 实现接口
        override fun onClick() {
        }

        override fun onLongClick() {
        }

        const val name = "Hello world"
        fun bar() {
            println("Companion object called")
        }
    }
}

fun A.Inner.kuozhan() { //扩展函数
    println("这是伴生对象的扩展函数")
}

fun main(args: Array<String>) {
    A.bar()
    A.name
    A.Inner.bar()
    A.Inner.name
    A.Inner.kuozhan()
}

总结

  1. Kotlin的接口与Java的相似,但是可以包含默认实现和属性(Java从第8版才开始支持)。
  2. 所有的声明默认都是 final?和 public?的。
  3. 要想使声明不是 final?的,将其标记为 open?。
  4. internal?声明在同一模块中可见。
  5. 嵌套类默认不是内部类。使用 inner?关键字来声明内部类,存储外部类的引用。
  6. sealed?类的子类只能嵌套在自身的声明中(Kotlin1.1允许将子类放置在同一文件的任意地方)。
  7. 初始化语句块和从构造方法为初始化类实例提供了灵活性。
  8. 使用 field?标识符在访问器方法体中引用属性的支持字段。
  9. 数据类提供了编译器生成的equal、hashCode、toString、copy和其他方法。
  10. 类委托帮助避免在代码中出现许多相似的委托方法。
  11. 对象声明是Kotlin中定义单例类的方法。
  12. 伴生对象(与包级别函数合属性一起)替代了Java静态方法和字段定义。
  13. 伴生对象与其他对象一样,可以实现接口,也可以拥有扩展函数和属性。
  14. 对象表达式是Kotlin中针对Java匿名内部类的替代品,并增加了诸如实现多个接口的能力和修改在创建对象的作用域中定义的变量的能力等功能。

原文地址:https://www.cnblogs.com/xxiaochao/p/11497252.html

时间: 2024-11-09 10:44:32

第四章(类、对象和接口)的相关文章

第四章 类与对象

一.面对对象编程的三个特性 封装性:经数据和对数据的操作封装在一起.通过抽象,从实例中抽取共同性质形成一般概念,例如类. 继承:子类可继承父类的属性和行为,继承父类所具有的数据和数据上的操作,同时增添子类独有的数据和数据上的操作. 多态:一是操作名称的多态,多个操作具有相同名字,这些操作所接受的消息必须不同:二是和继承有关的多态,同意操作被不同对象调用时产生不同行为. 二.类声明 类是JAVA程序的基本要素,JAVA应用程序有若干类组成,类声明的变量为对象变量. 类的定义两部分:类声明.类体 c

Java 核心技术 第四章 类与对象

类:构造对象的模板和蓝图.由类构造对象的过程称为创建类的实例. 对象的特征: 对象的行为 对象的状态 对象的标识 类之间的关系: 依赖 聚合 继承 对象与对象变量: new Date() new GregorianCalendar() new GregorianCalendar(1999, 11, 31) new GregorianCalendar(1999, Calendar.DECEMBER, 31) new GregorianCalendar(1999, Calendar.DECEMBER

【知识点总结】第四章 类与对象

面向对象程序设计的基本概念和特征 抽象性:对对象进行概括,抽出一类对象的公共性质并加以描述的过程.[数据抽象.行为抽象] 封装性:将抽象得到的数据.行为.功能相结合,形成一个有机的整体.就是将数据与操作数据的函数代码进行有机结合,形成"类",其中的数据和函数都是类的成员. 通过封装,对成员访问权限合理控制,使得不同类之间的相互影响减少到最低限度,进而增强数据的安全性和简化程序编写工作. 继承性 多态性 类的定义和实现 class 类名 { public: 公有成员(数据成员和函数成员)

java面向对象编程——第四章 类和对象

OO:面向对象 OOP:面向对象编程 OOA:面向对象分析 OOD:面向对象设计 结构化编程:从顶向下,将一个大问题分解成更小的任务,然后为每一个更小的任务编写一个过程.最后程序员会编写一个主过程来启动程序流程,随后根据程序流程走向,调用想要的其它过程. 对象是存在的具体实体,具有明确定义的特征和行为. 万物皆为对象,对象因我关注而产生. 面向对象:一种认识事物的方式,注重对事物整体的认知,最符合人类自然的思维习惯. 对象是数据封装的结果. 类是具有相同属性和行为的一组对象的集合. 在软件系统中

你不知道的JavasScript上篇&#183;第四章&#183;混合对象&#183;类

一.类的理论 1.类的核心概念:多态 是说父类的通用行为可以被子类用更特殊的行为重写 二.类的机制 1.构造函数 类实例是有一个特殊的类方法构造的,这个方法名通常和类名一致: 类构造函数属于类,构造函数大多需要用new来调. 2.类的多态 其实就是子类可以改写父类的同名方法也可以调用继承自父类的同名方法, 任何方法都可以引用继承层次中高层的方法,无论高层的方法名是否相同. 多态的另一个方面是,在继承链的不同层次中一个方法名可以多次被定义,调用方法时会自动选择合适的定义. 多态并不表示子类和父类有

第四章 python对象

4.1 Python 对象 所有的Python 对像都拥有三个特性:身份,类型和值.身份:每一个对象都有一个唯一的身份标识自己,任何对象的身份可以使用内建函数id()来得到.这个值可以被认为是该对象的内存地址.您极少会用到这个值,也不用太关心它究竟是什么. 类型对象的类型决定了该对象可以保存什么类型的值,可以进行什么样的操作,以及遵循什么样的规则.您可以用内建函数type()查看Python 对象的类型.因为在Python 中类型也是对象(还记得我们提到Python 是面向对象的这句话吗?),所

第四章:对象的组合——java并发编程实战

一.设计线程安全的类 找出构造对象状态的所有变量(若变量为引用类型,还包括引用对象中的域) 约束状态变量的不变性条件 建立对象状态的并发访问管理策略(规定了如何维护线程安全性) 1.收集同步需求(找出复合操作.多个变量遵循原子性的操作等) 2.依赖状态的操作(找出操作是否基于先验条件,例:取出当队列不为空) 3.状态的所有权(对象被哪些线程所有,哪些线程可以操作对象) 二.实例封闭 将数据封装在对象内部,可以将数据的访问限制在对象的方法上,确保简单正确的持有锁.(因为无需观察整个程序,只需检查当

python核心编程第四章 python对象

4–1. Python 对象.与所有 Python 对象有关的三个属性是什么?请简单的描述一下.  身份,类型和值. 4–2. 类型.不可更改(immutable)指的是什么?Python 的哪些类型是可更改的 (mutable),哪些不是? 如果对象支持更新操作,那么它的值就可以改变,否则它的值也是只读的.对象的值是否 可以更改被称为对象的可改变性(mutability) 数字 Scalar 不可更改 直接访问 字符串 Scalar 不可更改 顺序访问 列表 Container 可更改 顺序访

C# 开发 &mdash;&mdash; 数组类对象接口

数组类型是从抽象基类 Array 派生的引用类型,通过new运算符创建数组并将数组元素初始化为他们的默认值 一维数组 type[] arrayname; 数组的长度不是声明的一部分,而且数组必须在访问前初始化. foreach 语句声明一个迭代变量 -- 是数组的每个元素的只读副本 二维数组 type[,]  arrayName; int[,] arr = new int[2,2]{{1,2},{3,4}}; 可使用数组的Rank属性和GetUpperBound方法获取数组的行数和列数,然后遍历

Python核心编程笔记——第四章

第四章 Python对象 1.类型也是对象: a = 4;type(a)-><type 'int'>,这里"<type 'int'>"是一个类型对象(可以赋值给一个变量),可以使用 type(type(a)) 来验证 2.Python2.2开始,类和类型统一,类=类型,实例是类型的对象 3.任何对象都天生具有布尔值 4.整数对象,字符串对象,元组对象都是不可变对象,Python会高效的缓存整数和字符串对象,所以 a=3;b=1+2;(a is b)会返回T