scala类的介绍与操作02

1. 类的基本操作

1.1. 类的定义

object _01ClassOps {
	def main(args: Array[String]): Unit = {
		/*
			scala中类对应对象的构建,和java一模一样 使用关键字new,
			以及构造函数来完成实例的创建
			scala可以使用默认的无参构造器完成实例创建,
			同时一类如果有无参构造器,在创建对象的时候,可以省略掉()
		 */
		val p = new Person()
//		val p1 = new Person

//		p.name =
		p.setName("刘嘉豪")
		p.setAge(169)

		p.show()
	}
}


class Person {
	/*
		_的作用就相当于java中private String name代表默认值;
		如果要使用_,前面的成员变量就应该指定数据类型
	 */
	private var name:String = _

	private var age = 13
	def show(): Unit = {
		println(s"name=${name}\tage=${age}")
	}

	def setName(name:String):Unit = {
        //成员变量和局部变量命名冲突之后使用this关键字来进行区分
		this.name = name
	}

	def getName() = this.name
	//单行函数
//	def setAge(age:Int) = this.age = age
	def setAge(age:Int): Unit = {
		if(age < 0 || age > 150) {
			throw new RuntimeException("地球不欢迎你~")
		}
		this.age = age
	}

	def getAge = this.age
}

1.2. 类的构造

​ scala中有两类构造器——主构造器和辅助构造器。

object _02ConstructorOps {
	def main(args: Array[String]): Unit = {
		val p = new Person("华勇", 23)
		p.show()
	}
}

class Person() {

	private var name:String = _

	private var age:Int = _

	def Person(): Unit = {
		println("--Person()--是默认的构造器吗?")
	}

	//自定义构造器 自定义构造器的第一句话必须要调用其它构造器
	def this(name:String, age:Int) {
		this()
		this.name = name
		this.age = age
		println("---------this(name:String, age:Int)---------")
	}


	println("-------------构造器~----------------")
	def show(): Unit = {
		println(s"name=${name}\tage=${age}")
	}
}

本例中的这个和类的定义交织在一起的默认的构造器,是scala类中最重要的一个构造器——主构造器(默认的构造器是无参主构造器,定义在类名和类的{之间,省略了())。

其余的自定义构造器,也就是在类中通过def this(xxx)定义的构造器称之为辅助构造器,同时辅助构造器的第一句话,必须要通过this来调用本类主构造器或者其它辅助构造器

object _02ConstructorOps {
	def main(args: Array[String]): Unit = {
		val _3p = new Person(77)
		_3p.show()
	}
}

class Person(var name:String, var age:Int) {

	def Person(): Unit = {
		println("--Person()--是默认的构造器吗?")
	}

	def this() {
		this("嘿嘿", 33)
		println("---this() ---")
	}

	def this(name:String) {
		this()
		this.name = name
		println("---this(name:String) ---")
	}

	def this(age:Int) {
		this("龚天明")
		this.age = age
		println("---this(age:Int) ---")
	}
	println("-------------构造器~----------------")

	def show(): Unit = {
		println(s"name=${name}\tage=${age}")
	}
}

-------------构造器~----------------
—this() —
—this(name:String) —
—this(age:Int) —
name=龚天明 age=77

1.3. 内部类

object _03InnerClassOps {
	def main(args: Array[String]): Unit = {
		val outer = new Outer
		val inner = new outer.Inner()
		inner.show()
	}
}

class Outer { ooo =>
	 val x = 5

	class Inner { iii =>
		val x = 6

		def show(): Unit = {
			val x = 7
			System.out.println("x = " + x)
			System.out.println("inner class x = " + iii.x)
			System.out.println("Outer class x = " + ooo.x)
		}
	}
}

总结:scala的内部类和java的内部类的主要区别就在内部类对象的创建方式不一样。其次scala为了灵活的在内部类的局部访问内部类成员或者外部类的成员,可以给内部类和外部类的引用提供一个别名,方便操作。
也就是说,上例中这iii.x <=> this.x, ooo.x <=> Outer.this.x
内部类使用蛮多的一个地方:就是匿名内部类。

1.4. object对象

1.给scala类提供程序运行的入口,静态的main函数

2.给scala类也来提供静态成员——scala类的伴生对象来实现。
object中的所有的成员都是static静态

1.4. 单例

object _05ObjectOps {
    def main(args: Array[String]): Unit = {
        val s1 = Singleton.getInstance()
        val s2 = Singleton.getInstance()
        println(s1 == s2)
    }
}

//单例
class Singleton private () {
    var x = 5
}
/* 饿汉式
object Singleton {
    private val instance = new Singleton
    def getInstance(): Singleton = {
        instance
    }
}
 */
//懒汉式
object Singleton {
    private var instance:Singleton = _
    def getInstance(): Singleton = {
        if(instance == null) {
            Singleton.synchronized {
                if(instance == null) {
                    instance = new Singleton
                }
            }
        }
        instance
    }
}

1.5. 伴生对象

scala伴生对象的作用
1、给伴生类提供了类似于java中的静态成员
2、可以给scala的class提供一种新的对象构造方式
3、 在伴生对象中创建一个名为apply的方法,该apply方法的参数列表为class的构造函数的参数列表,二者保持对应
4、 返回值为本类,通过该apply方法来完成对象的构造
5、伴生对象,不仅可以访问对应伴生类的非私有成员,同时还可以访问对应伴生类的私有成员

object _06ObjectOps {
    def main(args: Array[String]): Unit = {
        val worker = Worker()
        worker.show()
        println("--------------")
        val w1 = Worker("柳泽宁", 15)
        w1.show()
    }
}
class Worker(name: String, age: Int) {
    def this() {
        this("old李", 35)
    }
    def this(name: String) {
        this()
    }
    def show(): Unit = {
        println(s"name: ${name}, age: ${age}")
    }
}
object Worker {//伴生对象
    def apply(): Worker = {
        new Worker()
    }
    def apply(name: String, age: Int): Worker = {
        new Worker(name, age)
    }
}

2. 类的继承体系

类与类之间的一个很重要关系——继承/扩展(extends)。

2.1. 类的扩展

继承的特点:

  1. 子类可以继承父类的所有非私有(private),非静态的成员(变量和成员方法)。
  2. 可以对父类的相关方法进行覆盖/重写
  3. 也可以添加自己独有的成员
  4. 被final修饰的父类成员,子类不可以继承
  5. 被protected修饰的父类成员,子类可以继承
  6. 子类覆盖父类的方法的异常,必须要大于等于父类的异常
  7. 子类的访问权限必须要大于等于父类
class Person {
	private var name:String = _
	protected var age:Int = 0


	def this(name:String, age:Int) {
		this()
		this.name = name
		this.age = age
	}

	def show(): Unit = {
		println(s"person's name is $name")
	}
}

class Student extends Person {
	age = 15
	def this(age:Int) {
		this()
		this.age  = age
	}
	override def show(): Unit = {
		super.show()//子类调用父类的成员通过super关键字
		println(s"Student's age is $age")
	}
}

person’s name is null
Student’s age is 18

override在java中是一个注解,用来表示该方法是继承的,scala中是一个关键字,必须要添加在重写的方法前面,除非该方法是抽象的。

2.2. 类型检查和转换

使用isInstanceOf来进行类型判断,asInstanceOf进行类型转换。需要注意的是这两个操作都是对象的方法。

object _02EqualsOps {
	def main(args: Array[String]): Unit = {
		val w1 = new Worker("雷德言", 33)
		val w2 = new Worker("雷德言", 33)
		println(w1.equals(w2))
	}
}

class Worker {
	private var name:String = _
	private var age:Int = _
	def this(name:String, age:Int) {
		this()
		this.age = age
		this.name = name
	}
	override def equals(obj: Any): Boolean = {
		if(!obj.isInstanceOf[Worker]) //类型检查
			false
		else {//类型转换
			val that = obj.asInstanceOf[Worker]
			this.name.eq(that.name) && this.age == that.age
		}
	}
}

同时scala提供另一种更加简洁的写法,来处理这些类型检查和类型转换——模式匹配

override def equals(obj: Any): Boolean = {
    obj match {//模式匹配
        case that:Worker => {
            this.name.eq(that.name) && this.age == that.age
        }
        case _ => false
    }
}

2.3. 受保护字段和方法

被修饰为protected的age字段,不能在子类中被访问,但是通过scala的特定访问权限修饰设置,

  • 在访问修饰符后面使用[]指定要访问的package,比如protected[extendz]——代表了该字段只能在extendz包及其子包下面被访问。
  • 这实际上是更加精准的访问权限控制。
  • private后面也可以加[extendz],和上面类似
object _01ProtectedOps {
    def main(args: Array[String]): Unit = {
        val stu = new Student
        val person = new Person()
        person.name = "清华学姐"
        person.age = 23

        stu.makeFriends(person)
    }
}
class Person {
    var name: String = "刘照路"
    protected[extendz] var age: Int = 18
//    protected[this] var age: Int = 18
    private[extendz] var gender = "guy"

    def show(): Unit = {
        println(s"${name}, age: ${age}, gender: ${gender}")
    }
}

class Student extends Person {
    name = "刘照路2"
    age = 19
    def makeFriends(person: Person): Unit = {
        println(s"姓名为:${this.name}, 年龄为${this.age}的小哥哥和${person.name}, 年龄为:${person.age}的小姐姐成为了红颜知己~")
    }
}

被protected[this]所修饰的变量,只能在本类,及其子类中被调用,但不可以被子类对象调用。
在这里插入图片描述

2.4 访问权限修饰符

scala中的访问权限修饰符就只有这么两个:private、protected,缺省相当于public

2.5 子类调用父类构造

super.show()调用父类的方法
子类只能通过主构造器来调用父类的构造器。

object _01ExtendsOps {
	def main(args: Array[String]): Unit = {
		val stu = new Student("李烨培")
		stu.show()
	}
}

class Person {
	private var name:String = _
	protected var age:Int = 0

	println("父类Person的主构造器-------")
	def this(name:String, age:Int) {
		this()
		this.name = name
		this.age = age
		println("----父类Person的辅助构造器this(name:String, age:Int)------")
	}
	def this(name:String) {
		this(name, 0)
		this.name = name
		this.age = age
		println("----父类Person的辅助构造器this(name:String)------")
	}
	def show(): Unit = {
		println(s"person's name is $name")
	}
}

class Student(name:String) extends Person(name) {
	println("子类Student的主构造器")
	age = 15
	def this(age:Int) {
		this("zhangsan")
		this.age  = age
		println("----子类Student的辅助构造器------")
	}
	override def show(): Unit = {
		super.show()
		println(s"Student's age is $age")
	}
}

父类Person的主构造器-------
----父类Person的辅助构造器this(name:String, age:Int)------
----父类Person的辅助构造器this(name:String)------
子类Student的主构造器
person’s name is 李烨培
Student’s age is 15

2.5. 重写字段和方法

​ 说白了就是在字段前面加上一个override关键字即可。最主要的作用就是父类中定义的非私有非protected的字段,子类如果想要定义个同名的字段,此时就需要使用override关键字完成覆盖,如果不用报错。

​ 被覆盖的字段只能被val修饰。

​ 方法的覆盖和java的覆盖是一样的。

2.6 匿名子类

匿名子类,其实说白了就是没有名字的类,通常匿名的类就是只调用一次的,没有必要进行定义,在运行时完成创建即可。

object _03AnonymousSubClassOps {
    def main(args: Array[String]): Unit = {
        fire(new Manager("黄世仁"))
        println("---------------------------------------")
        val m = new Manager("黄世仁"){
            override def manage(): Unit = {
                super.manage()
                println("还有升级版:克扣工资")
            }
            def haha(): Unit = {
                println("哈哈哈")
            }
        }
        m.haha()

        fire(m)

    }
    def fire(manage: Manager): Unit = {
        manage.manage()
        println("所以要炒了经理的鱿鱼~")
    }
}
class Manager(name: String) {
    def manage(): Unit = {
        println(s"行为为${name}的经理正在对员工吆五喝六~")
    }
}

2.7抽象类和抽象方法、字段

  • scala中的抽象类 抽象方法 抽象字段(这在java中不存在)
  • 一个类中的方法或者字段只有定义,没有实现,那么吧这些方法或者字段称之为抽象的方法和字段,
  • 而又抽象方法或者字段的类,我们称之为抽象类,用abstract关键字来进行修饰
  • 同样,抽象方法和字段的abstract关键字可以省略,而类上面abstract可不能省略。
  • 子类如果复写了父类的抽象的成员,是可以省略掉override关键字的,但是复写非抽象成员该关键字必须要加。
object _04AbstractOps {
    def main(args: Array[String]): Unit = {
        val cat = new Cat()
        cat.sleep()
        println("------------------------------")
        val fish = new Fish()
        fish.sleep()
    }
}

/**
 * 定义一个抽象类
 */
abstract class Animal {
    val leg: Int
    def sleep():Unit
    def dead(): Unit = {
        println("动物固有一死,或清蒸,或红烧,或爆炒,这真的是太难了~")
    }
}
class Cat extends Animal {
    val leg: Int = 4

    def sleep(): Unit = {
        println("喵星人,蜷缩成一团睡觉~")
    }
}
class Horse extends Animal {
    override val leg: Int = 4

    override def sleep(): Unit = {
        println("站着睡觉的还有谁!")
    }
}
class Fish extends Animal {
    override val leg: Int = 0

    override def sleep(): Unit = {
        println("睁着眼睛睡觉,太难了我~")
    }
}

2.8 trait特质

  • trait特质:
  • 不管是java还是scala的继承,有一个特点:只能单继承,不能多继承,在java中来弥补这个缺陷怎么解决:
  • 1、可以多层继承
  • 2、进行多实现(implements interface)
  • 在多实现这个接口的时候,比较痛苦,如果接口方法比较少还好,但是如果方法很多,实现起来非常的麻烦
  • 所以scala有了trait这样一个概念来弥补java中的interface只能由抽象方法的缺陷
  • 所以scala中的trait比java中的接口interface内容更加的丰富,既可以拥有抽象,也可以有拥有非抽象,当trait特质中的所有
  • 方法都抽象的时候,我们就可以理解其为java中的接口。
  • trait在进行调用的时候和scala的类的调用一样,都要使用关键字extends,而java的接口实现用implements
  • java的实现多接口的时候通过多个,来进行分割。很遗憾scala扩展多个trait的时候使用关键字with来进行分割。
  • 比java中的接口还牛的一点是,可以做到动态的运行时的扩展特质————特质的混入
  • 如果scala的一个类,既要扩展一个类,又要扩展特质,那么先写类,其次用with连接trait特质
object _05TraitOps {
    def main(args: Array[String]): Unit = {
        val logger = new ConsoleLogger
        logger.log("roma was not built in one day~")
        println("--------------------------")
        val fileName = "E:/data/out/scala/fileLogger.txt"
        val fLoger = new FileLogger(fileName) with MySerializable
        fLoger.log("god help those who help themselves.")
        fLoger.log("love is blind.")
        fLoger.close()
        fLoger.serialize("书到用时方恨少,绝知此事要躬行。")
    }
}

trait Logger {
    def log(msg: String): Unit

    def show(): Unit = {
        println("show~")
    }
}

trait MySerializable {
    //完成了序列化
    def serialize(msg: String): Unit = {
        println("serilaize: " + msg)
    }
}

class ConsoleLogger extends Logger {
    override def log(msg: String): Unit = {
        println("consoleLogger: " + msg)
    }
}

class FileLogger(fileName: String) extends Logger /*with MySerializable */{
    private val bw = new FileWriter(fileName, true)
    override def log(msg: String): Unit = {
        bw.write(msg)
        bw.write("\r\n")
        bw.flush()
    }
    def close(): Unit = {
        if(bw != null) {
            bw.close()
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值