//scala类
class Person {
//用val定义的成员变量,只提供了getter方法
val id = "1234"
//用var定义的成员变量,提供了setter和getter方法
var name = "jack"
var age = 20
//方法
def sleep()={
println("正在休息。。。。。")
}
}
object Person extends App {
val p = new Person()
//获取和修改成员变量
//p.id = "23432" 报错val修饰的成员变量不能修改
println("id:" + p.id)
p.age = 22
println("age:" + p.age)
println(p.name)
p.sleep()
}
Scala中的每个类都有一个主构造器,主构造器的参数直接放在类后面,并且主构造器会执行类中定义所有语句
//主构造器放在类名后面
class Student (val n :String,var a :Int){
val name :String = n
//var修饰可修改
a = a + 1
var age = a
//使用占位符时需要指定参数的类型
//scala类中所使用的占位符”_”,只有在声明var变量时才可以使用
var sex : String= _
println("主构造器执行了类中定义的所有语句")
//构造器(构造方法) 辅构造器
def this(n :String,a :Int,sex :String){
//调用主构造器,不可省略
this(n,a)
println("调用了辅构造器")
this.sex = sex
}
//方法
def study(s :String): Unit ={
println(name + "在学习" + s)
}
}
object Student extends App{
//主构造器
val stu1 = new Student("jack",20)
println(stu1.age) //21
//赋值操作会在其他语句之后执行
stu1.age = 30
stu1.study("scala")
println(stu1.age) //30
//辅构造器
val stu2 = new Student("lisi",20,"男")
stu2.study("hadoop")
}
执行结果:
主构造器执行了类中定义的所有语句
21
jack在学习scala
30
主构造器执行了类中定义的所有语句
调用了辅构造器
lisi在学习hadoop
//主构造器放在类名后面
class Student private(val n :String,var a :Int){
val name :String = n
//var修饰可修改
a = a + 1
var age = a
//使用占位符时需要指定参数的类型
//scala类中所使用的占位符”_”,只有在声明var变量时才可以使用
var sex : String= _
println("主构造器执行了类中定义的所有语句")
//构造器(构造方法) 辅构造器
private def this(n :String,a :Int,sex :String){
//调用主构造器,不可省略
this(n,a)
println("调用了辅构造器")
this.sex = sex
}
//方法
def study(s :String): Unit ={
println(name + "在学习" + s)
}
}
object Test extends App{
val stu1 = new Student("张三",20)
val stu2 = new Student("李四",30,"女")
}
运行结果会出错:在主构造器或辅构造器修饰为private后,访问权限仅限:本类和伴生对象中使用
伴生对象:指的是对象名与类名相同的对象
当类中的成员变量为私有时,有如下两种解决方法
1、在Student类中添加:getter、setter方法
2、使用伴生对象
//scala类
class Person {
private var name :String = _
private var age :Int = _
//方法
def sleep()={
println(s"年龄为:$age 的 $name 正在休息。。。。。")
}
}
object Test extends App{
//创建对象
var p = new Person()
//p.id 报错并不能访问私有的成员
p.sleep()
}
解决方法:
//scala类
class Person { //默认的无参主构造器
private var name :String = _
private var age :Int = _
//get和set方法
def setName(name: String) ={
this.name = name
}
def getName: String ={
this.name
}
def setAge(age :Int)={
this.age = age
}
def getAge : Int = {
this.age
}
//全参构造器(辅构造器)
def this(name :String,age : Int){
this()
this.name = name
this.age = age
}
//方法
def sleep()={
println(s"年龄为:$age 的 $name 正在休息。。。。。")
}
}
object Test extends App{
//创建对象 主构造器
var p = new Person()
//p.id 报错并不能访问私有的成员
p.setAge(20)
p.setName("jack")
p.sleep()
//辅构造器
var p1 = new Person("lisi",30)
p1.sleep()
}
object相当于class的单个实例(单例模式),通常在里面放一些静态的field或者method
在Scala中没有静态方法和静态字段,但是可以使用object这个语法结构来达到同样的目的
object的单例模式
class Session {}
object Session extends App {
//相当于静态块
val session = new Session
//相当于静态方法
def getSession() : Session={
session
}
}
object Test1 extends App {
//单例对象
val session1 = Session.session
val session2 = Session.getSession()
}
伴生对象的解释:
如果有一个class,还有一个与class同名的object,那么就称这个object是class的伴生对象,class是object的伴生类
要求: 伴生类和伴生对象必须存放在一个.scala文件中
特点: 伴生类和伴生对象的最大特点是,可以相互访问(可以访问私有成员)
//伴生类
class Student private{
//私有成员
private var name :String = _
private var age :Int = _
//get和set方法
def setName(name: String) ={
this.name = name
}
def getName: String ={
this.name
}
def setAge(age :Int)={
this.age = age
}
def getAge : Int = {
this.age
}
//私有全参构造器(辅构造器)
private def this(name :String,age : Int){
this()
this.name = name
this.age = age
}
//方法
def study(s :String): Unit ={
println(name + "在学习" + s)
}
}
//伴生对象
object Student{
val stu1 = new Student()
stu1.name = "zhangsan"
stu1.age = 20
stu1.study("java")
val stu2 = new Student("lisi",30)
}
//伴生类
class Student private{
//私有成员
private var name :String = _
private var age :Int = _
//get和set方法
def setName(name: String) ={
this.name = name
}
def getName: String ={
this.name
}
def setAge(age :Int)={
this.age = age
}
def getAge : Int = {
this.age
}
//私有全参构造器(辅构造器)
private def this(name :String,age : Int){
this()
this.name = name
this.age = age
}
//方法
def study(s :String): Unit ={
println(name + "在学习" + s)
}
}
//伴生对象
object Student{
//无参
def apply(): Student = new Student()
//有参
def apply(name : String,age : Int): Student = new Student(name,age)
}
//测试类
object Test1 extends App {
//利用伴生对象创建对象
var stu = Student()
//相当于 var stu = Student.apply()
stu.setName("张三")
stu.setAge(20)
stu.study("java")
//var stu = Student.apply(name,age)
var stu2 = Student("李四",30)
stu2.study("scala")
}
继承是面向对象的概念,用于代码的可重用性。被扩展的类称为超类或父类, 扩展的类称为派生类或子类。
Scala 中,让子类继承父类,与 Java 一样,也是使用 extends 关键字;
//父类
class Person{
var name :String = _
var age :Int = _
}
//子类
class Student extends Person{
//子类特有的方法
def study(s : String): Unit ={
//name是继承的person中的变量
println(name + "在学习" + s)
}
}
object Test1 extends App {
var stu = new Student()
stu.name = "jack"
stu.age = 30
stu.study("scala")
}
继承就代表,子类可继承父类的field和method,然后子类还可以在自己的内部实现父类没有的,子类特有的 field 和method,使用继承可以有效复用代码
在Scala中的继承:
1、private修饰的field和method不可以被子类继承,只能在类的内部使用
2、使用final修饰符时,修饰类:类不能被继承、修饰field和method:不能被覆写
override的使用场景:
1、Scala中,如果子类要覆盖父类中的一个非抽象方法,必须要使用 override 关键字
2、子类可以覆盖父类的val修饰的field,只要在子类中使用 override 关键字即可
(注意:针对父类中的var修饰的field,子类不能覆写)
super的应用场景: super.父类中的方法
在子类覆盖父类方法后,如果在子类中要调用父类中被覆盖的方法,则必须要使用super关键字(显示的指出要调用的父类方法)
override和super的应用案例:
//父类
class Phone {
//val不可修改的变量
val id = "12345"
def call = println("打电话")
}
//子类
class NewPhone extends Phone {
//覆写父类中的val变量和非抽象方法必须使用override关键字
override val id: String = "6789"
override def call: Unit = {
//调用父类的方法使用super关键字
super.call
println("开启视频")
}
}
object Test1 extends App {
var p = new NewPhone()
//调用子类覆写的方法
p.call
}
在Scala中同样提供了protected关键字来修饰field和method,方便子类去继承父类中的field和method
//父类
class Person{
//protected 是为继承提供的
//protected [this] 只允许在本类和子类中使用(子类的伴生对象不能访问)
protected [this] var name :String = _
protected var age :Int = _
protected def say(s :String)= println(s)
}
//子类
class Student extends Person{
//子类特有的方法
def study(s : String): Unit ={
//name是继承的person中的变量
println(name + "在学习" + s)
}
def setName(n :String)={
this.name = n
}
}
object Student extends App {
var stu = new Student()
//这里不能直接访问父类的name成员
stu.setName("张三")
stu.age = 20
stu.study("scala")
}
创建子类对象时,会自动调用子类相应的构造器:
1、调用子类主构造器
2、调用子类辅助构造器,辅构造器会再去调用主构造器
和java一样,创建子类对象时,也会先去调用父类的构造器:子类主构造器去调用父类中的构造器
一个类中,如果含有一个抽象方法或抽象field,就必须使用abstract将类声明为抽象类,该类是不可以被实例化的
在子类中覆盖抽象类的抽象方法时,可以不加override关键字
//抽象类 抽象field和方法都需要放在方法抽象类中
abstract class Person{
//抽象的field没有初始值
var name :String
var age :Int = _
//抽象方法没有方法体实现
def study(s: String)
def say:String
}
//子类继承抽象类
class Student extends Person{
//覆写所有的抽象内容 同时可以省略override
def study(s : String): Unit ={
//name是继承的person中的变量
println(name + "在学习" + s)
}
override var name: String = _
override def say: String = "hello"
}
object Student extends App {
var stu = new Student()
stu.name = "jack"
stu.age = 20
var hello = stu.say
stu.study("scala")
}
在实例化了子类的对象,并将其赋予了父类类型的变量后,父引用无法去调用子类中特有的方法,如果想要调用子类中特有的方法,应该类型转换
在java中,进行类型转换时,为了避免类型转换异常,会使用instanceof先判断类型,再进行类型转换
//父类
class Person{
var name :String = _
var age :Int = _
def eat(s :String)={
println("吃" + s)
}
}
//子类
class Student extends Person{
//子类特有的方法
def study(s : String): Unit ={
//name是继承的person中的变量
println(name + "在学习" + s)
}
//子类覆写父类的方法
override def eat(s: String): Unit = {
println(this.name + "吃" + s)
}
}
object Test extends App {
//声明一个父类型变量指向子类型
var person : Person = new Student()
person.name = "jack"
person.age = 20
person.eat("米饭")
//判断person对象是否为student的实例
if (person.isInstanceOf[Student]){
//将person对象转成student实例
var stu : Student = person.asInstanceOf[Student]
//调用子类对象特有的方法
stu.study("java")
}
}
Scala中的Trait(特质)相当于Java的接口,但实际上它比接口要功能强大,与传统的接口不同之处是:它除了可以定义抽象方法外还可以定义属性和方法的实现
在Scala中没有 implement 的概念,无论继承类还是trait,统一都是 extends
类继承后,必须实现所有的抽象方法,实现时不需要使用 override 关键字
trait Demo1{
def sayHello(s :String)
}
//子类继承需要重写抽象方法
class Person extends Demo1 {
override def sayHello(s: String): Unit = {
println("打招呼," + s)
}
}
object TraitDemo1 extends App {
val p = new Person()
p.sayHello("jack")
}
Scala不支持对类进行多继承,但是支持多重继承 trait,使用 with 关键字即可
trait Demo1{
def sayHello(s :String)
}
trait Demo2{
def say():String
}
class Person extends Demo1 with Demo2 {
override def sayHello(s: String): Unit = {
println( say() + s)
}
override def say(): String = "你好"
}
object TraitDemo1 extends App {
val p = new Person()
p.sayHello("scala")
}
在Traint中除了可以书写抽象方法外,还可以书写:抽象字段、具体方法、具体字段
Trait高级知识: 创建对象实例时,trait加入到对象实例中
可在创建类的对象时,为该对象指定混入某个trait,且只有混入了trait的对象才具有trait中的方法,而其他该类的对象则没有
格式: val 引用变量 = new 类名() with Trait
在创建对象时,使用with关键字指定混入某个trait
trait TraitLogger{
def log(msg : String)={
println("日志内容:------" + msg)
}
}
trait MyLogger extends TraitLogger{
override def log(msg: String): Unit = {
println(System.currentTimeMillis() + msg)
}
}
class Person extends TraitLogger{
log("打印日志。。。")
}
object TraitDemo2 extends App {
val p = new Person() with MyLogger
}
当去调用多个trait中的方法时,首先会从最右边的trait中的方法开始执行,然后依次往左边的trait执行,形成一个调用链条(这个特性非常强大:是设计模式中责任链模式的一种具体实现)
trait TraitOne{
def handle(data : String)={
println("获取数据--" + data)
}
}
trait TraitTwo extends TraitOne{
override def handle(data : String)={
println("处理数据--"+ data)
super.handle(data)
}
}
trait TraitThree extends TraitOne{
override def handle(data : String)={
println("分析数据--"+ data)
super.handle(data)
}
}
class RequestResult(val data : String) extends TraitThree with TraitTwo {
def getParam={
println("参数:" + data)
//调用多个trait中方法名相同的方法
handle(this.data)
}
}
object traitdemo3 extends App {
val p = new RequestResult("大数据")
p.getParam
}
trait traitOne{
def getName : String
def valid(data : String):Boolean={
data.equals(this.getName)
}
}
class Person(data :String) extends traitOne{
override def getName: String = this.data
}
object traitdemo4 extends App {
val p = new Person("数据")
if (p.valid("测试")){
println("数据合法")
}else{
println("数据不合法")
}
}
2.4.1构造机制
在Trait中只有无参构造(主构造器)
trait TraitOne{
println("TraitOne的构造器。。。。")
}
trait TraitTwo{
println("TraitTwo的构造器。。。。")
}
class TraitChlid extends TraitOne with TraitTwo {
println("TraitChlid的构造器。。。。")
}
object traitdemo5 extends App {
val t = new TraitChlid()
}
子类没有继承父类,只继承多个独立的Trait(Trait没有继承)时,构造机制:
从extends后面第一个Trait构造器开始执行,依次向后面的Trait构造器执行
class Parent{
println("Parent的构造器。。。。")
}
trait MyTrait{
println("MyTrait的构造器。。。。")
}
trait TraitOne extends MyTrait{
println("TraitOne的构造器。。。。")
}
trait TraitTwo extends MyTrait{
println("TraitTwo的构造器。。。。")
}
class TraitChlid extends Parent with TraitOne with TraitTwo {
println("TraitChlid的构造器。。。。")
}
object traitdemo5 extends App {
val t = new TraitChlid()
}
子类继承了父类的同时,也继承了多个Trait(Trait也有继承)时,构造机制:
1、父类的构造器
2、多个Trait从左向右依次执行(构造Trait时,先构造父Trait)
注意:如果多个Trait继承同一个父Trait,则父Trait只会构造一次
3、子类的构造器
2.4.2Trait中的field初始化
提前定义Trait中的field
trait traitHello{
//抽象field
val msg : String
println("信息的长度:"+ msg.length)
}
class TraitClass extends {override val msg :String = "初始化值"} with traitHello{
//方法一在类上覆写抽象field
}
object traitdemo6 extends App {
val t = new TraitClass()
//方法二在实例化时覆写抽象field
/**
* val t = new {
* override val msg :String = "初始化值"
* } with TraitClass with traitHello
*/
}