[1.1] 面向对象编程之get-set方法与构造器详解
2016-08-01 19:20
483 查看
场景
一、肿么理解scala中的val与var关键字?有人说:val标识常量,且有公有get方法、私有set方法 - 有私有set方法吗?二、代码:
class Person5(name:String){ } class Person6(val name:String){ }
中字段name加 val前缀与不加,有什么区别?
由于scala代码被scala编译器编译成字节码字,最终在JVM上运行.因此,以上两个问题,可以通过反编译工具将字节码字反编译成我们熟悉的java代码,类比理解scala中的val与var 进行求证。
知识点
一. get与set方法与private关键字
scala字段默认由private关键字修饰。其中, val 标识常量-无set方法,有公有get方法、var标识变量-具有公有 set、get方法。set方法的命名规则:属性名称_=(字段类型) 或 属性名称_$eq(字段类型)
;get方法命名规则:属性名称()。
由显式private修饰的字段只有私有方法。
二、构造器
主构造器中的参数可以有 val 与 var 等修饰,也可以没有 - 而辅助构造器中的参数不能 有val与var修饰 。类中没有定义在任何方法或者是代码块之中的代码,就是主constructor的代码-类初始化时会被执行。辅助构造器中必须直接或者间接调用主构造器,以完成类的初始化
实验
先介绍一个JDK自带的反编译工具 : javap.$ javap -c -p className 表示 : 对字节码className进行反编译,且显示所有的类与成员.
好,来看一个案例吧!
一、val标识的字段无私有set方法的证明
package cool.pengych.objectoriented /** * function: fun面向对象 之 案例详解 val,var,private关键字 与 类的主构造器,辅助构造器 */ class Person(val father:String) { //公有 set, get方法 var name:String = _ //字段需要显式赋值(这里值为 _,相当于赋null),而不像java可以不赋值 //公有get,无set方法 val friend = "ivy" //私有set,get方法 private var age = 18 //私有get方法,无set方法 private val interests = "basketball" /* * 1. 虽然是 age 是private 的,但是在类的内部,可以通过自定义方法,改变 age 的值 * 2. 由于由于interests是 val 的,因此在类的内部也不能改变其值 */ def setAge(age:Int){ this.age = age } def setInterests (interests:String){ // this.interests = interests; } /* * 1. 辅助构造器中第一行必须要直接或者间接调用主构造器 * 2. 为了保证类结构的一致性,辅助构造器中,不能传递 val 与 var等修饰的常量与变量 * eg. this方法如果传 var age : Int这种变量就不行 */ def this(father:String = "spark",age:Int = 18){ this(father) // 直接调用主构造器 this.age = age } def this(father:String,son:String){ this // 间接调用主构造器-通过调用辅助构造器间接调用主构造器. // 这里其实调用的是 辅助构造器 this(father:String = "spark",age:Int = 18) - 参数默认都有值,所以可以不传 } } object HelloOOP{ def main(args: Array[String]): Unit = { val person = new Person("spark") person.name = "ben" person.setAge(27) println(person.friend) // println(person.interests) // println(person.age) private 修饰的常量与变量 ,其set与get方法都是私有的,因此通过get方法获取其值 } }
执行以下命令,进行反编译:
pengyucheng@sparker:~$ scalac Person.scala pengyucheng@sparker:~$ javap -c -p cool/pengych/objectoriented/Person.class
反编译后的部分结果如下(简单起见,删除了一些冗长的代码):
Compiled from "Person.scala" public class cool.pengych.objectoriented.Person { private final java.lang.String father; // [snail注]证明了:字段默认就是由private关键字修饰的? // 因为scala代码的主构造器中的father没有用private修饰,而这里出现了private. private java.lang.String name; private final java.lang.String friend; private int age; private final java.lang.String interests; public java.lang.String father(); 1: getfield #31 // Field public java.lang.String name(); 1: getfield #35 // Field public void name_$eq(java.lang.String); 2: putfield #35 // Field public java.lang.String friend(); //[snail注]val修饰的字段只有公有get方法,没有set方法 Code: 0: aload_0 1: getfield #40 // Field friend:Ljava/lang/String; 4: areturn private int age();//get方法的名称:属性名称() Code: 0: aload_0 1: getfield #42 // Field age:I 4: ireturn private void age_$eq(int); //[注]set方法的名称:1、属性名称_=(字段类型) 2、属性名称_$eq(字段类型) Code: 0: aload_0 1: iload_1 2: putfield #42 // Field age:I 5: return private java.lang.String interests(); Code: 0: aload_0 1: getfield #46 // Field interests:Ljava/lang/String; 4: areturn public void setAge(int); Code: 0: aload_0 1: iload_1 2: invokespecial #49 // Method age_$eq:(I)V 5: return public void setInterests(java.lang.String); Code: 0: return public cool.pengych.objectoriented.Person(java.lang.String);// [snail注]类的主构造器 public cool.pengych.objectoriented.Person(java.lang.String, int); public cool.pengych.objectoriented.Person(java.lang.String, java.lang.String); }
看到了吗?只有var修饰的字段,比如说age才有set方法:age_$eq(int)-注意方法内部调用的是下面的putfield方法,而get方法调用的是底层JVM的getfield方法。
private void age_$eq(int); Code: 0: aload_0 1: iload_1 2: putfield #42 // Field age:I 5: return
二、主构造器中参数有无 val或者var修饰的区别
反编译package cool.pengych.scala.objectoriented
/**
* Created by 彭宇成 on 2016/8/6.
*/
class Person5(name:String){ } class Person6(val name:String){ }
后的结果如下:
Compiled from "Person5.scala" public class cool.pengych.scala.objectoriented.Person5 { public cool.pengych.scala.objectoriented.Person5(java.lang.String); //[注]类中没有 name属性 Code: 0: aload_0 1: invokespecial #13 // Method java/lang/Object."<init>":()V 4: return } Compiled from "Person5.scala" public class cool.pengych.scala.objectoriented.Person6 { private final java.lang.String name; public java.lang.String name();[注]val修饰的构造器参数name,反编译后类中有 name属性 Code: 0: aload_0 1: getfield #13 // Field name:Ljava/lang/String; 4: areturn public cool.pengych.scala.objectoriented.Person6(java.lang.String); Code: 0: aload_0 1: aload_1 2: putfield #13 // Field name:Ljava/lang/String; 5: aload_0 6: invokespecial #20 // Method java/lang/Object."<init>":()V 9: return }
总结
scala中字段默认由 private 关键字修饰的;var标识的字段有公有set与get方法,而val标识的字段只有公有get方法。无val与var修饰的类主构造器参数,不会映射成类的同名字段。有val或者var修饰的主构造器参数,会映射成类的同名字段 - 编译器会帮我们自动生成相关的get与set方法,以及类的含参构造器 - 这在很大程度上增强了scala代码的简洁性。
辅助构造器必须在首行直接或者间接调用主构造器,以完成类的初始化。
相关文章推荐
- 详解ActionScript中set和get方法,java中set和get方法
- javascript中set与get方法详解
- 详解PHP的__set()、__get()、__isset()、unset()四个方法
- 详解php的魔术方法__get()和__set()使用介绍
- 关于面向对象编程中很多人用get()和set()方法,而不用public的一点总结
- get()和set()方法详解
- 关于面向对象编程中很多人用get()和set()方法,而不用public的一点总结
- PHP 魔术方法__set() __get() 方法详解
- ios 中 set get 方法 便利构造器的创建 Block 动画
- MATLAB面向对象编程get与set方法实现
- 魔术方法__set, __get(), __isset(), unset()详解
- python property 与get/set方法详解
- 详解php的魔术方法__get()和__set()使用介绍
- 详解php的魔术方法__get()和__set()
- PHP 魔术方法__set() __get() 方法详解
- 详解php的魔术方法__get()和__set()使用介绍
- __set() __get() 方法详解
- GET与SET用法详解
- 自动化测试之路(三) ruby里的get与set方法
- PHP __set() __get() __isset() __unset() 四个方法的应用