第一章 类
第二章 对象
2.1 构造器
- 主构造器的声明直接放置于类名之后
class ConstructorClass() {
// 类体
}
// 当使用new构建对象时,等同于调用类的主构造器
val obj = new ConstructorClass()
// ()可加可不加
- 主构造器会执行类定义中的所有语句
class ConstructorClass() {
// 执行主构造器时,类体中所有语句都会执行
}
val obj = new ConstructorClass()
- 主构造器传递参数
// 如果主构造器无参数,小括号可省略
// 构造器也是方法(函数),传递参数和使用方法和前面的函数部分内容没有区别
class ConstructorClass( p : String ) {
println("参数为 = " + p)
}
val obj = new ConstructorClass("123")
- 辅助构造器名称为this(这个和Java是不一样的),多个辅助构造器通过不同参数列表进行区分
class Person() {
private var sname = ""
private var iage = 0
// 辅助构造器无论是直接或间接,最终都一定要调用主构造器,执行主构造器的逻辑
def this( name : String ) {
this() // 放在第一行
sname = name
}
def this( name : String, age : Int ) {
this(name) //调用之前已经声明过该构造器
iage = age
}
}
- 如果想让主构造器变成私有的,可以在()之前加上private,这样用户只能通过辅助构造器来构造对象了
class ConstructorClass private () {
}
val obj = new ConstructorClass() // (X)
2.2 单例对象
- java单例对象
// Java
class Singleton {
private Singleton() {}
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
- Scala中没有静态的概念,所以为了实现Java中单例模式的功能,可以直接采用类对象方式构建单例对象
object Singleton {
}
2.3 伴生对象
在Scala中,如果在
同一个源码文件
中,同时存在使用object声明的类对象(Person)以及使用class声明的类(Person),那么这个类对象就是该类的伴生对象,而这个类就是这个类对象的伴生类。
// person.scala
class Person { // 伴生类
}
object Person { // 伴生对象
}
注:类和它的伴生对象可以相互访问私有属性或方法,他们必须存在
同一个源文件
中。必须同名
。
从技术的角度来讲,伴生对象和伴生类其实是两个不同的类,伴生对象所对应的类可以简单的理解为伴生类的辅助
工具类
。而伴生对象就是这个辅助工具类的单例对象,专门用于处理伴生类中静态资源的相关功能
.
伴生对象既然是一个单例对象,就意味着类已经声明过了,所以,伴生(类)对象是不能声明构造器
的
2.4 apply()方法
因为伴生对象可以处理静态资源,所以完全可以通过伴生对象提供的方法对伴生类进行处理
object Person {
def apply() = { // 在伴生对象中实现apply方法。
return new Person() // 这里也可以采用单例模式实现
}
}
…
val p = Person()
// 此处不需要使用new关键字,而是直接增加小括号,在执行时,会自动调用伴生对象中的apply方法。返回伴生类实例对象
2.5 应用程序对象 APP
object ScalaApp extends App {
// 同main , 继承App可以作为程序的入口
println("Hello, Scala!")
}
2.6 枚举对象
Scala中没有枚举类型,定义一个扩展Enumeration类的对象,并以Value调用初始化枚举中的所有可能值,模拟枚举类型。
object LightColorEnum extends Enumeration {
val Red = Value(0, "Stop")
val Yellow = Value(1, "Slow")
val Green = Value(2, "Go")
}
第三章 属性
3.1 构造器参数做属性
- 构造器参数, 未添加修饰符, 参数仅仅作为局部变量:
Scala类的主构造器函数是可以添加参数的。如果参数未用任何修饰符修饰,那么这个参数是局部变量
class Person( name : String ) { // 此处的name未加任何修饰,是局部变量,无法通过对象进行访问
}
var p = new Person("lisi")
- 使用val修饰的构造器参数, 升级为类的只读属性
class Person( val name : String ) {
}
var p = new Person("lisi")
// 这里调用对象的name属性,其实并不是属性,而是方法,因为方法无参数,
// 所以省略了小括号,感觉和调用属性一样,这体现了Scala语言访问一致性
println(p.name)
- 使用var修饰的构造器参数, 升级为类的成员属性, 并会提供setter和getter方法
class Person( var name : String ) {
}
var p = new Person("lisi")
p.name = "wangwu" // setter
println(p.name) //getter
- 类比java
class Person(){
private String name;
private int age;
// 构造方法
public Person(String name, int age){
this.name = name;
this.age = age;
}
setName()...
getName()...
setAge()...
getAge()...
}
使用Scala实现如下:
class Person(var name : String, var age : Int){
// scala 完成了上述java定义Person类的所有功能
}
3.2 Bean属性
- 属性必须显式初始化
Scala中类的属性必须显式的初始化, 或者使用
_
自动赋值
class User {
// 声明属性 Scala必须显示初始化,故使用_让编译器自动赋值
var username: String = _
var age: Int = _
def login(): Boolean = {
true
}
}
- 使用var 声明属性
scala中给类声明属性,默认是私有的,但是底层提供的setter和getter方法,对象.属性 就等于是在掉getter,属性 = 值 就等于在调setter
class Student {
var name: String = _
// 默认 name 是私有的, 但是底层提供了setter和getter方法
// setter: student.name = "zhangsan"
// getter: student.name
}
- 使用private var声明属性
如果给属性增加private修饰符,那么属性无法在外部访问,因为底层的setter和getter是被私有的
class Student {
// 如果给属性增加private修饰符,那么属性无法在外部访问,因为底层的setter和getter是被私有的
private var age: Int = _
// 底层:
private void setAge(int age){}
private int getAge(){}
}
- 使用val 声明属性
如果声明的属性使用val ,那么属性是私有的,并且使用final修饰,底层只有getter方法,没有setter
class Student {
val emial: String = ""
// 底层
private final string emial = "";
private string getEmial(){}
}
- 使用@BeanProperty注解显示调用setter和getter
class Person {
@BeanProperty var name: String = null
}
var p = new Person()
p.setName("zhaoliu")
println(p.getName())
第四章 方法
4.1 成员方法
4.2 静态方法
scala 中没有static的概念, 如果要定义静态方法,需要在类的伴生对象中定义,
package com.lz.scala.day04
/**
* @ClassName Demo02_ScalaObjectField
* @Description: 伴生对象
* @Author MAlone
* @Date 2019/11/8
* @Version V1.0
**/
// 伴生类 (定义成员,非静态)
class Student {
private val sname = "zhangsan"
}
// 伴生对象 (作用一:定义静态, 作用二:创建伴生类的对象)
object Student {
// 静态方法
def test(): Unit = {
// 伴生对象可以访问伴生类的私有属性
new Student().sname
}
}
4.3 apply()方法
使用apply(),可以在创建对象时, 省略new关键字
// 使用伴生对象创建伴生类的对象,需要提供特殊的方法apply,
object Student {
def apply: Student = new tudent()
def test(): Unit = {
// 伴生对象可以访问伴生类的私有属性
new Student().sname
}
}
object Demo04_StudentTest {
def main(args: Array[String]): Unit = {
// 采用伴生对象创建伴生类Student
val student = Student
// 默认是在调用Student.apply()
}
}
4.4 构造方法
4.4.1 主构造方法
在类的后面声明的构造方法就是主构造方法
class User2(s: String) {
// 故这里的类体也叫构造方法体
println("主构造方法1")
println(s)
println("主构造方法2")
}
类比构造方法和一般方法(
类也是函数
)
class User(s : String ) : Unit = {}
def user(s: String) : Unit = {}
// 无返回值 ,省略 :Unit=
class User(s : String ){}
def user(s: String){}
// 如果没有参数
class User {}
def user {}
// 故类也是函数
4.4.2 辅助构造方法
在主构造方法中声明的构造方法就是辅助构造方法, 方法名使用
this
scala构建对象可以通过辅助构造方法创建,但是辅助构造方法必须调用主构造方法
class User2(s: String) {
// 故这里的类体也叫构造方法体
println("主构造方法1")
println(s)
println("主构造方法2")
// 在主构造方法中声明的构造方法就是辅助构造方法,方法名使用this
def this(s: String, ss: String) {
this(s)
println("辅助构造方法2")
}
def this() {
this("辅助构造方法1", "****")
}
}
第五章 包
5.1 作用域
同一个源码文件, 可以多次声明
package com.lz.scala
class Person{
val name = "Nick"
def play(message: String): Unit ={
}
}
等同于
package com.lz
package scala
class Person{
val name = "Nick"
def play(message: String): Unit ={
}
}
等同于
package com.lz{
package scala{
class Person{
val name = "Nick"
def play(message: String): Unit ={
}
}
}
}
注:位于文件顶部不带花括号的包声明在对当前整个文件内的包声明有效。
通过以上形式,总结如下:
- 包也可以像嵌套类那样嵌套使用(包中有包)。
- 作用域原则:可以直接向上访问。即,子包中直接访问父包中的内容。(即:作用域)
- 源文件的目录和包之间并没有强制的关联关系
- 可以在同一个.scala文件中,声明多个并列的package
- 包名可以相对也可以绝对,比如,访问BeanProperty的绝对路径是:
root. scala.beans.BeanProperty
5.2 包对象
包中只能定义类.
使用包对象, 可以在包中定义属性和方法
package object scala {
//每个包都可以有一个包对象。你需要在父包中定义它,且名称与子包一样。
var name = "zhangsan"
}
5.3 包可见性
- 当访问权限缺省时,scala默认为public访问权限
class Person {
// 此时属性为public访问权限,任何地方都能访问
var name = "zhangsan"
}
- 私有权限
class Person {
// 此时属性为私有的,只在类的内部和伴生对象中可用
private var name = "zhangsan"
}
- 受保护权限
class Person {
// scala中受保护权限比Java中更严格,只能子类访问,同包无法访问
protected var name = "zhangsan"
}
- 包访问权限
package com.lz.scala
class Person {
// 增加包访问权限后,private同时起作用
private[scala] val pname="zhangsan"
//当然,也可以将可见度延展到上层包:
private[atguigu] val description="zhangsan"
}
5.4 导入包
- 在Scala中,import语句可以出现在任何地方,并不仅限于文件顶部。
class User {
import scala.beans.BeanProperty
@BeanProperty var name : String = ""
}
注:import语句的效果一直延伸到包含该语句的块末尾
2) 在Java中如果想要导入包中所有的类,可以通过通配符星号,Scala中采用下划线
class User {
import scala.beans._ // 这里采用下划线作为通配符
@BeanProperty var name : String = ""
}
- 如果不想要某个包中全部的类,而是其中的几个类,可以采用选取器(大括号)
def test(): Unit = {
import scala.collection.mutable.{HashMap, HashSet}
var map = new HashMap()
var set = new HashSet()
}
5.5 重命名和隐藏
如果引入的多个包中含有相同的类,那么可以将不需要的类进行重命名进行区分
- 重命名:
import java.util.{ HashMap=>JavaHashMap, List}
import scala.collection.mutable._
var map = new HashMap() // 此时的HashMap指向的是scala中的HashMap
var map1 = new JavaHashMap(); // 此时使用的java中hashMap的别名
- 如果某个冲突的类根本就不会用到,那么这个类可以直接隐藏掉。
import java.util.{ HashMap=>_, _}
var map = new HashMap() // 此时的HashMap指向的是scala中的HashMap
第六章 继承
和Java一样使用
extends
关键字,在定义中给出子类需要而超类没有的字段和方法,或者重写超类的方法。
如果类声明为final,他将不能被继承。如果单个方法声明为final,将不能被重写
scala明确规定,只要出现override情况,一定要显式声明关键字override
6.1 抽象类
6.1.1 抽象属性
属性只有声明, 没有初试化
java中没有抽象属性, 只有抽象方法,
scala之所以有抽象属性, 是因为:
定义的属性,在底层生成的是setter和getter方法
// 抽象类
abstract class PersonAbs {
// scala 中属性也可以重写,因为属性也可以抽象,属性抽象只有声明,而没有初始化,那么就是抽象属性
// 底层实现:抽象属性在编译为class文件时,不产生属性,但是产生getter方法
var sex: String
}
6.1.2 抽象方法
明抽象方法,只有声明 ,没有实现,不需要abstract关键字声明
// 抽象类
abstract class PersonAbs {
// 声明抽象方法,只有声明 ,没有实现,不需要abstract关键字声明
def test()
}
6.2 重写
6.2.1 重写父类抽象属性
补全即可
// 抽象类
abstract class PersonAbs {
var sex: String
}
class User3 extends PersonAbs {
// 重写属性,补全属性
override var sex: String = _
}
6.2.2 重写父类非抽象属性
必须加override关键字,但是不能重写父类var声明的变量,要是val
// 抽象类
abstract class PersonAbs {
val email: String = "ddd"
}
class User3 extends PersonAbs {
// TODO Scala如果子类重写了父类的非抽象属性,必须加override关键字,但是不能重写父类var声明的变量,要是val
override val email: String = "yyy"
}
6.2.3 重写父类抽象方法
补全即可
// 抽象类
abstract class PersonAbs {
// 声明抽象方法,只有声明 ,没有实现,不需要abstract关键字声明
def test()
}
class User3 extends PersonAbs {
// 重写抽象方法:补全方法 override 可加可不加
override def test(): Unit = {
println("test")
}
}
6.2.4 重写父类非抽象方法
必须加override
// 抽象类
abstract class PersonAbs {
def test1() = {
println("test1")
}
}
class User3 extends PersonAbs {
// TODO Scala如果子类重写了父类的非抽象方法,必须加override关键字
override def test1(): Unit = {
super.test1()
println("test1 child")
}
}
6.3 超类的构造
- java
- 父类
package com.lz.extend;
/**
* @ClassName Person
* @Description: TODO
* @Author MAlone
* @Date 2019/12/16
* @Version V1.0
**/
public class Person {
public Person(String s) {
}
}
- 子类
package com.lz.extend;
/**
* @ClassName Emp
* @Description: TODO
* @Author MAlone
* @Date 2019/12/16
* @Version V1.0
**/
public class Emp extends Person {
public Emp(String s) {
// 如果父类没有无参构造, 在子类的构造方法中 必须使用super显式的调用父类的构造方法
super(s);
// 如果父类有无参构造, 那么可以不使用super, 因为默认在子类的构造方法中会加上super
}
public Emp() {
// 如果父类没有无参构造, 在子类的构造方法中 必须使用super显式的调用父类的构造方法
super("ss");
System.out.println("SS");
}
}
- scala
class Person( name: String){
}
class Emp(name : String) extends Person(name){
// scala中没有super . 在父类后面加括号实现
}