Scala的基本语法(四) 类

java scala的区别

​ 1) Java是面向对象的编程语言,由于历史原因,Java中还存在着非面向对象的内容:基本类型(int,float…) ,null,静态方法等(object 替代)。

​ 2) Scala语言来自于Java,所以天生就是面向对象的语言,而且Scala是纯粹的面向对象的语言,即在Scala中,一切皆为对象。

Scala对象创建对象流程分析

​ 1) 加载类的信息(属性信息和方法信息)
​ 2) 在内存中(堆)给对象开辟空间
​ 3) 使用父类的构造器(主构造器/辅助构造器)完成父类的初始化 (多个父类)
​ 4) 使用本类的主构造器完成初始化( age = 90 name = “null”)
​ 5) 使用本类的辅助构造器继续初始化(age =20,name = “小倩”)
​ 6) 将对象在内存中的地址赋给 p 这个引用

总结

  • scala 中的object是单例对象,相当于java中的工具类,可以看成是定义静态的方法的类。object不可以传参数。另:Trait不可以传参数
  • 类不能声明为public,默认就是public
  • 属性的定义类型可以为任意类型,包含值类型或引用类型,属性必须显示的初始化。若暂时不赋值,也可以必须给定数据类型,使用符号_(下划线),让系统分配默认值
  • 如果赋值为null,则一定要加类型,因为不加类型, 那么该属性的类型就是Null类型
  • scala中的class类默认可以传参数,默认的传参数就是默认的构造函数。重写构造函数的时候,必须要调用默认的构造函数。
  • 使用object时,不用new,使用class时要new ,并且new的时候,class中除了方法不执行,其他都执行。
  • 如果在同一个文件中,object对象和class类的名称相同,则这个对象就是这个类的伴生对象,这个类就是这个对象的伴生类。可以互相访问私有变量。
  • 伴生对象的功能特性并不在类的作用域内,如类无法直接使用伴生对象的方法 必须加类名

构造器

  • Scala构造器作用是完成对新对象的初始化,构造器没有返回值,会执行除方法外的所有语句

  • 多个辅助构造器通过不同参数列表进行区分, 在底层就是构造器重载,辅助构造器无论是直接或间接,最终都一定要调用主构造器

  • 如果想让主构造器变成私有的,可以在()之前加上private,这样用户不能直接通过主构造器来构造对象了class C private(){}

  • <父类如果没有空参构造方法 子类继承时要传入参数,如自定义Spark数据源receiver

  • 构造器

    class Person2(name: String) {
    public Person2(String name) {}  //在底层实现 
    }
    
  • 可以把主构造器设置为有参 辅助构造器为def this()空参,在定义中调用有参主构造器,这样子类继承时可以继承空参的父类。

  • 可以将子类参数传递给继承的父类构造器

    class Emp (name:String) extends Person(name){}//class Person(name:String)是父类构造器,子类又可以继承父类的name
    
构造器参数
  1. 如果Scala类的主构造器的形参未用任何修饰符修饰,这个参数将升级为字段(或局部变量),如果没有方法使用,则没有改字段。

  2. 如果参数使用val关键字声明,那么Scala会将参数作为类的私有的只读属性使用

  3. 如果参数使用var关键字声明,那么那么Scala会将参数作为类的成员属性使用,并会提供属性对应的xxx()[类似getter]/xxx_$eq()[类似setter]方法,即这时的成员属性是私有的,但是可读写。


修饰符

  • 没有修饰符的var变量,在编译时会被声明为private类型,但提供公共的get和set方法,即name,name_=

  • 没有修饰符的val变量,在编译时会被声明为private类型,但只提供公共的get方法

  • 使用private修饰的var变量.只有私有的get与set,如需访问,需要自定义get与set

  • 使用private[this]修饰的var变量,为对象所私有,同一个类的不同对象不能相互访问该属性,也就是对象隔离级

  • @BeanProperty 生成java风格的get与set 以及默认的

    scala 访问控制底层实际只用了两种修饰符: private public 。不管变量是否是private ,scala先将其定义成private属性,如果允许外界访问(如未定义private var),getter setter方法就会被设置成public,否则(如加了private var或者作为主构造器的参数)getter setter被设置为private 或者没有getter(private val)等。(protect例外 即便底层是public)

  • 虽然scala的变量定义是底层都是private修饰的, 但如果父类private def修饰的的方法及public的getter setter方法,子类仍然可以通过调用父类的getter setter,来获取修改继承自父类的private修饰的属性。

val 变量

private final int val_val = 18;
public int val_val() { return this.val_val; }

var 变量

 private String var_var = "coder";
 public String var_var() { return this.var_var; } 
 public void var_var_$eq(String x$1) { this.var_var = x$1; } 

private val 变量

 private final int age;  // final修饰
 private int age() { return this.age; } 

private var 变量

 private String pri_var = "private var";
 private String pri_var() { return this.pri_var; }      //pri_var
 private void pri_var_$eq(String x$1) { this.pri_var = x$1; }   //pri_var._方法

@BeanProperty val

 private final String BeanP_val = "@BeanProperty val";   //得到2个方法
 public String BeanP_val() { return this.BeanP_val; } 
 public String getBeanP_val() { return BeanP_val(); }

@BeanProperty var

//@BeanProperty var adress="beijing"   //得到4个方法 
 private String adress = "beijing";
 public String adress() { return this.adress; } 
 public void adress_$eq(String x$1) { this.adress = x$1; } 
 public void setAdress(String x$1) { this.adress = x$1; } 	//setter
 public String getAdress() { return adress(); }		//getter

无任何修饰的参数 无方法引用 class Person(name:String,age:Int)

class Person(name:String,age:Int)
--------------------------------------------------
public Person(String name, int age){}  //源码中升级为字段 如果没有方法使用,则没有该字段

无任何修饰的参数 有方法引用

 class Person(name:String,age:Int) def sellHello: Unit ={println(name+Int)  } //以默认public方法为例
--------------------------------------------------
 private final String name; //因为是final 子类无法继承
 public void sellHello() { 
 Predef..MODULE$.println(new StringBuilder().append(this.name).append(Int..MODULE$).toString());
}

包的使用

  1. 包也可以像嵌套类那样嵌套使用(包中有包), 这个在前面的第三种打包方式已经讲过了,在使用第三种方式时的好处是:程序员可以在同一个文件中,将类(class / object)、trait 创建在不同的包中,这样就非常灵活了。[案例+反编译] / 案例参考前面的即可。

  2. 作用域原则:可以直接向上访问。即: Scala中子包中直接访问父包中的内容, 大括号体现作用域。(提示:Java中子包使用父包的类,需要import)。在子包和父包 类重名时,默认采用就近原则,如果希望指定使用某个类,则带上包名即可。

  3. 父包要访问子包的内容时,需要import对应的类等

  4. 可以在同一个.scala文件中,声明多个并列的package(建议嵌套的pakage不要超过3层)

  5. 包名可以相对路径也可以绝对路径,比如,访问BeanProperty的绝对路径是:
    root. scala.beans.BeanProperty ,在一般情况下:我们使用相对路径来引入包,只有当包名冲突时,使用绝对路径来处理

引入包

import语句可以出现在任何地方,import语句的作用一直延伸到包含该语句的块末尾。这种语法的好处是:在需要时在引入包,缩小import 包的作用范围,提高效率

  1. Java中如果想要导入包中所有的类,可以通过通配符*,Scala中采用下 _

  2. 如果不想要某个包中全部的类,而是其中的几个类,可以采用选取器,使用{} 括起来即可。

  3. 如果引入的多个包中含有相同的类,那么可以将类进行重命名进行区分,这个就是重命名。

包对象

​ 包可以包含类、对象和特质trait,但不能包含函数/方法或变量的定义。这是Java虚拟机的局限。为了弥补这一点不足,scala提供了包对象的概念来解决这个问题。

1)每个包都可以有一个包对象。你需要在父包中定义它。

  1. 包对象名称需要和包名一致,一般用来对包的功能补充

  2. 当属性访问权限为默认时,从底层看属性是private的,但是因为提供了xxx_$eq()[类似setter]/xxx()[类似getter] 方法,因此从使用效果看是任何地方都可以访问)

  3. 当方法访问权限为默认时,默认为public访问权限

  4. private为私有权限,只在类的内部和伴生对象中可用 【案例演示】

  5. protected为受保护权限,scala中受保护权限比Java****中更严格,只能子类访问同包无法访问 (编译器从语法层面控制)

  6. 在scala中没有public关键字,即不能用public显式的修饰属性和方法。【案演】

  7. scala设计者将访问的方式分成三大类:

​ (1) 处处可以访问public (2) 子类和伴生对象能访问protected (3) 本类和伴生对象访问 private

  1. 包访问权限(表示属性有了限制。同时包也有了限制),这点和Java不一样,体现出Scala包使用的灵活性。 当然,也可以将可见度延展到上层包private[atguigu] val description="zhangsan"说明:private也可以变化,比如protected[atguigu], 非常的灵活.

在这里插入图片描述

posted @ 2019-12-01 12:34  曲水修竹  阅读(119)  评论(0编辑  收藏  举报