Scala面向对象
Scala的面向对象思想和Java的面向对象思想和概念是一致的,但Scala语法和Java不同,补充了更多的功能。
一.关于package
1.包的管理方式
Scala有两种包的管理风格:
-
1)和Java的包管理风格相同,每个源文件一个包,包名用“.”进行分隔以表示包的层级关系,如
com.example.scala
- 包名和源文件所在路径不要求必须一致
-
2)另一种风格,通过嵌套的风格表示层级关系,如下
package com{
package example{
package scala{
object Test{
def main(args: Array[String]): Unit = {
println("Hello World!!!")
}
}
}
}
}
包名和源文件所在路径不要求必须一致:
- 将以上代码复制到Test.scala文件中
scalac
编译
第二种风格有以下特点:
- 1)一个源文件中可以声明多个package
- 2)子包中的类可以直接访问父包中的内容,而无需导包
- 3)父包访问子包需要导包
package com {
//导包语句可以出现在程序的任意位置
import com.example.Inner //父包访问子包需要导包
//外层包中的类
object Outer {
val out: String = "out"
def main(args: Array[String]): Unit = {
println(Inner.in)
}
}
package example{
//内层包中的类
object Inner {
val in: String = "in"
def main(args: Array[String]): Unit = {
println(Outer.out) //子包访问父包无需导包
}
}
}
}
package other {
}
2.包对象
在Scala中可以为每个包定义一个同名的包对象,定义在包对象中的成员,作为其对应包下所有class和object的共享变量,可以被直接访问。
package object com{
val shareValue="share"
def shareMethod()={}
}
1)若使用Java的包管理风格,则包对象一般定义在其对应包下的package.scala
文件中,包对象名与包名保持一致
- 包名:scala.collection = 包对象名:scala包下的collection
2)如采用嵌套方式管理包,则包对象可与包定义在同一文件中,但是要保证包对象与包声明在同一作用域中
package com {
object Outer {
val out: String = "out"
def main(args: Array[String]): Unit = {
//调用包对象的name属性
println(name)
}
}
}
package object com {
val name: String = "com"
}
3.导包说明
1)和Java一样,可以在顶部使用import导入,在这个文件中的所有类都可以使用。
2)局部导入:什么时候使用,什么时候导入——在其作用范围内都可以使用
3)通配符导入:import java.util._
4)给类起名:import java.util.{ArrayList=>JL}
5)屏蔽类:import java.sql.{Date=>_,Array=>_,_}
6)导入相同包的多个类:import java.util.{HashSet, ArrayList}
7)导入包的绝对路径:new _root_.java.util.HashMap
注意:Scala中的三个默认导入分别是
- import java.lang._
- import scala._
- import scala.Predef._
二.类和对象
在Java/Scala语言中,类是创建对象的模板,是客观事物在人脑中的主观反映;而只要是客观存在的事物都是对象(万物皆对象):
- 类:可以看成一个模板
- 对象:表示具体的事物
1.定义类
1)Java中的类
- 如果类是public的,则必须和文件名一致。
- 一般,一个.java文件有一个public类
注意:Scala中没有public,一个.scala中可以写多个类。
2)Scala基本语法
[修饰符] class 类名 {
类体
}
说明:
- 1)Scala语法中,类并不声明为public,所有这些类都具有公有可见性(即默认就是public)
- 2)一个Scala源文件可以包含多个类
2.属性
属性是类的一个组成部分
1)基本语法
[修饰符] var|val 属性名称 [:类型] = 属性值
注:
- 1)在Scala语言中,类、方法、属性默认修饰符是public,但是没有public关键字
- 2)对于Scala中的默认属性,底层会用private修饰,同时提供公开的设置以及获取属性的方法----面向封装
- 3)如果编译后要生成满足JavaBean规范的get和set方法的话,需要在属性上加@BeanProperty注解
- 作用:实现对一些框架进行支持
- 4)如果想给属性赋默认值,需要在声明的时候,赋 _:数值数据类型是各种各样的0,而其他数据类型则为null
object TestField {
def main(args: Array[String]): Unit = {
//创建对象
val std: Student05 = new Student05()
//通过对象.的方式访问属性
std.name = "lisi"
println(std.name) //lisi
println(std.sex) //null
}
}
class Student05{
//在Scala语言中,属性、方法、类默认的修饰是public
//但是public 不能显式加 类似java中default
//底层生成的字节码文件对属性用private进行修饰,提供了公开的获取|设置属性值的方法
//作用1:符合面向对象的封装特性
var name:String = "zhangsan"
//如果想生成符合JavaBean规范的get|set方法,需要在属性上加一个注解@BeanProperty
//作用2:对一些框架进行支持
@BeanProperty
var age:Int = 18
//如果想给属性赋默认值,需要在声明的时候,赋_
var sex:String = _
}
Student类的反编译结果:
三.封装
封装就是把抽象出的数据和对数据的操作封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作(成员方法),才能对数据进行操作。
Java封装操作如下:
- 1)将属性进行私有化
- 2)提供一个公共的set方法,用于对属性赋值
- 3)提供一个公共的get方法,用于获取属性的值
Scala中默认public属性,底层实际为private,并通过get方法(obj.field())和set方法(obj.field_=(value))对其进行操作。所以Scala并不推荐将属性设为private,再为其设置public的get和set方法的做法。
如果属性设置为private:其编译结果对应的属性及方法都为私有
1.权限访问
Java中:
- private 私有的,只能在当前类中被访问
- default 默认的,当前类以及同包的其他类
- protected 受保护的,可以在本类、同包的其它类以及非同包的子类中被访问
- public 公开的,所有类
Scala中:
- 在scala中,类、方法、属性默认就是public修饰,但是没有public关键字
- private 私有的:只能在当前类以及伴生对象中使用
- protected 受保护的:比Java中的权限设置更加严格,同类、子类可以访问,同包其它类不能访问
- private[包名] 包访问权限:可以让指定的包进行访问
2.方法
基本语法
def 方法名(参数列表) [:返回值类型] = {
方法体
}
3.创建对象
1)基本语法
val | var 对象名 [:类型] = new 类型()
2)说明:
- 1)val修饰对象,不能改变对象的引用(即:内存地址),可以改变对象属性的值。
- 2)var修饰对象,可以修改对象的引用和修改对象的属性值
- 3)自动推导变量类型不能多态,所以多态需要显示声明
class Person {
var name: String = "canglaoshi"
}
object Person {
def main(args: Array[String]): Unit = {
//val修饰对象,不能改变对象的引用(即:内存地址),可以改变对象属性的值。
val person = new Person()
person.name = "bobo"
// person = new Person()// 错误的
println(person.name)
}
}
4.构造器
1.构造器(构造方法)的作用:
- 构造对象
- 初始化属性(给对象的属性赋值)
2.Java中构造器
- 1)方法名和类名保持一致
- 2)构造方法没有返回值类型
- 3)构造方法可以重载
和Java一样,Scala构造对象也需要调用构造方法,并且可以有任意多个构造方法。
Scala类的构造器包括:主构造器和辅助构造器
3.Scala中构造器(构造方法)
- 1)主构造方法
- 在声明类的同时,主构造方法也被声明
- 在一个类中,主构造方法只能有一个
- 如果主构造方法没有参数,那么以及调用的时候,小括号可以省略的
- 2)辅助构造方法
- 方法名必须叫this
- 辅助构造方法可以重载,可以有多个,编译器通过参数的个数及类型来区分
- 辅助构造方法中的第一行必须直接或者间接调用主构造方法
- 构造器调用其他另外的构造器,要求被调用构造器必须提前声明
4.基本语法如下:
//如果想让主构造器变成私有的,可以在()之前加上private
class 类名 [private](形参列表) { // 主构造器
// 类体
def this(形参列表) { // 辅助构造器
}
def this(形参列表) { //辅助构造器可以有多个...
}
}
5.案例:
//(1)如果主构造器无参数,小括号可省略
// class Person (){
class Person {
var name: String = _
var age: Int = _
//(2)方法名必须叫this,且可以重载
def this(age: Int) {
//辅助构造方法中的第一行直接调用主构造方法
this()
this.age = age
println("辅助构造器1")
}
//构造器调用其他另外的构造器,要求被调用构造器必须提前声明
//注意辅助构造函数顺序:辅助构造器1必须在2之前声明
def this(age: Int, name: String) {
//辅助构造方法中的第一行调用辅助构造器1——达到间接调用主构造方法目的
this(age)
this.name = name
println("辅助构造器2")
}
println("主构造器")
}
object Person {
def main(args: Array[String]): Unit = {
val person1 = new Person(18) //输出结果:
println("-----------------------")
val person2 = new Person(18,"zhangsan")
}
}
输出结果:
主构造器
辅助构造器1
-----------------------
主构造器
辅助构造器1
辅助构造器2
5.构造器参数
Scala类的主构造器函数的形参包括三种类型:未用任何修饰、var修饰、val修饰
- 1)未用任何修饰符修饰,这个参数就是一个局部变量(在外部访问不了)
- 2)var修饰参数,作为类的成员属性使用,可以修改
- 3)val修饰参数,作为类只读属性使用,不能修改
//1)只提供无参的主构造:可以省略小括号
class Student1{
var name:String = _
var age:Int = _
}
//2)在声明主构造方法参数的时候,如果参数前什么也不加,那么参数就作为当前类的局部变量使用,不能作为类的属性被访问
//在scala语言中,以下写法比较少,如果这样写,那就是受java毒害太深了
class Student2(namePararm:String,ageParam:Int){
var name:String = namePararm
var age:Int = ageParam
}
//3)如果需要将参数作为属性被访问的话,那么在参数声明前加var或者val关键字
class Student3(var name:String, var age:Int){
def m1(): Unit ={
println(name)
println(age)
}
}
四.继承
基本语法:
class 子类名 extends 父类名 { 类体 }
scala继承特点:
- 1)子类继承父类的属性和方法
- 2)scala是单继承
- 3)继承的调用顺序:父类构造器->子类构造器
五.抽象属性和抽象方法
1.基本语法
- 1)定义抽象类: 通过abstract关键字标记抽象类
- 2)定义抽象属性:一个属性没有初始化,就是抽象属性
- 3)定义抽象方法:只声明而没有实现的方法,就是抽象方法
//1)定义抽象类
abstract class Person {
// 2)定义抽象属性
val name: String
//3)定义抽象方法
def hello(): Unit
}
//实现类
class Teacher extends Person {
val name: String = "teacher"
def hello(): Unit = {
println("hello teacher")
}
}
2.继承&重写
- 1)如果父类为抽象类,那么子类需要将抽象的属性和方法实现,否则子类也需声明为抽象类
- 2)如果重写(实现)抽象属性或者方法,那么override关键字可以省略
- 如果重写(覆盖)非抽象属性或者方法,那么override关键字不能省略,必须得加
- 3)子类中调用父类的方法使用super关键字
- 可以通过super关键字调用父类的方法,但是不能super调用父类的属性
- 4)子类对父类抽象属性进行实现,父类抽象属性==可以用var修饰;
- 子类对父类非抽象属性重写,父类非抽象属性只支持val类型,而不支持var。
- 因为var修饰的为可变变量,子类继承之后就可以直接使用,没有必要重写
- 5)Scala中,属性和方法都是动态绑定,而Java中只有方法为动态绑定——多态
- 静态绑定(编译器绑定)
在编译阶段,确定属性或者方法所属类型 - 动态绑定
在运行阶段,根据实际创建的对象类型来决定属性 或者方法所属类型
- 静态绑定(编译器绑定)
class Person {
val name: String = "person"
def hello(): Unit = {
println("hello person")
}
}
class Teacher extends Person {
//重写父类的name常量;如果name是变量,没有必要重写,直接重写赋值使用即可
override val name: String = "teacher"
//重写hello方法
override def hello(): Unit = {
println("hello teacher")
}
}
object Test {
def main(args: Array[String]): Unit = {
val teacher: Teacher = new Teacher()
println(teacher.name)
teacher.hello()
//多态:都为动态绑定
val teacher1:Person = new Teacher
println(teacher1.name) //teacher
teacher1.hello() //hello teacher
}
}
3.匿名子类
Java一样,scala可以通过包含带有定义或重写的代码块的方式创建一个匿名的子类。
//定义抽象类
abstract class Person {
val name: String
def hello(): Unit
}
object Test {
def main(args: Array[String]): Unit = {
//使用匿名子类:实现抽象类Person
val person = new Person {
override val name: String = "teacher"
override def hello(): Unit = println("hello teacher")
}
}
}
六.多态
多态:同一个对象,多种不同形态
- 父类引用指向子类对象,或者是接口指向实现类
- 只能调用其引用类型中定义的方法(编译看左)
- 静态绑定(编译期绑定):在Java语言中,在程序编译的时候,确定属性所属的类型
- 在运行的时候,会执行子类中覆盖的方法(运行看右)
- 动态绑定(运行期绑定):在程序执行的时候,看实际创建对象的类型是什么,然后进行调用,方法属于动态绑定
Java中只有方法为动态绑定,而Scala中属性和方法都是动态绑定。
public class Test {
public static void main(String[] args) {
//不存在多态的情况
Teacher tea = new Teacher();
System.out.println(tea.name);//teacher
tea.hello();//hello teacher
//存在多态的情况:方法为动态绑定,属性为静态绑定
Person tea2 = new Teacher();
System.out.println(tea2.name);//person
tea2.hello();//hello teacher
//tea2.sayHi(); 编译不能被通过
}
}
class Person{
String name = "person";
public void hello(){
System.out.println("hello Person");
}
}
class Teacher extends Person11{
String name = "teacher";
public void hello(){
System.out.println("hello teacher");
}
public void sayHi(){
System.out.println("sayHI teacher");
}
}
七.单例对象(伴生对象)
Scala语言是完全面向对象的语言,所以并没有静态的操作(即在Scala中没有静态的概念)。但是为了能够和Java语言交互(因为Java中有静态概念),就产生了一种特殊的对象来模拟类对象,该对象为单例对象。
若单例对象名与类名一致,则称该单例对象为这个类的伴生对象,这个类的所有“静态”内容都可以放置在它的伴生对象中声明。
1.单例对象语法
object Person{
val country:String = "China"
}
说明
- 1)单例对象采用object关键字声明
- 2)单例对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致。
- 3)单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。
//(1)伴生对象采用object关键字声明
object Person {
var country: String = "China"
}
//(2)伴生对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致。
class Person {
var name: String = "bobo"
}
object Test {
def main(args: Array[String]): Unit = {
//(3)伴生对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。
println(Person.country)
}
}
2.伴生对象的apply方法
- 1)通过伴生对象的apply方法,实现不使用new方法创建对象。
- 2)如果想让主构造器变成私有的,可以在()之前加上private。
- 3)apply方法可以重载。
- 4)Scala中obj(arg)的语句实际是在调用该对象的apply方法,即obj.apply(arg)
- 用来统一面向对象编程和函数式编程的风格。
- 5)当使用new关键字构建对象时,调用的其实是类的构造方法;当直接使用类名构建对象时,调用的其实时伴生对象的apply方法。
object Test {
def main(args: Array[String]): Unit = {
//(1)通过伴生对象的apply方法,实现不使用new关键字创建对象
val p1 = Person() //实际上是调用的Person.apply()方法
println("p1.name=" + p1.name)
val p2 = Person("bobo")
println("p2.name=" + p2.name)
}
}
//(2)如果想让主构造器变成私有的,可以在()之前加上private
class Person private(cName: String) {
var name: String = cName
}
object Person {
//3)apply方法可以重载
def apply(): Person = {
println("apply空参被调用")
new Person("xx")
}
def apply(name: String): Person = {
println("apply有参被调用")
new Person(name)
}
//注意:调用apply方法也可以创建其它类型对象,并不一定是伴生类对象
}
注意:调用apply方法也可以创建其它类型对象,并不一定是伴生类对象
3.创建对象的方式总结
1)Java创建对象的方式
- new
- 反射
- 工厂
- 克隆
- 反序列化
2)Scala创建对象的方式
- a)new:底层调用类的构造方法
- b)类():底层调用的是apply方法
- apply方法定义在类的伴生对象中
单例设计模式
- 1)构造方法私有化
- 2)提供私有静态属性,接收单例对象
- 3)公共的、静态的getInstance方法
object TestSingleton {
def main(args: Array[String]): Unit = {
val std1: Student1 = Student1.getInstance()
println(std1)
val std2: Student1 = Student1.getInstance()
println(std1)
}
}
//1.懒汉式
object Student1{
// 2)提供私有静态属性,接收单例对象
private var s:Student1 = null
// 3)公共的、静态的getInstance方法
def getInstance():Student1={
if(s == null){
s = new Student1
}
s
}
}
//1)主构造方法私有化
class Student1 private(){}
//2.饿汉式
object Student2{
// 2)提供私有静态属性,接收单例对象
private var s:Student2 = new Student2
// 3)公共的、静态的getInstance方法
def getInstance():Student2={
s
}
}
//1)主构造方法私有化
class Student2 private(){}
八.Trait:特质
Scala语言中,采用特质trait(特征)来代替接口的概念,也就是说,多个类具有相同的特质(特征)时,就可以将这个特质(特征)独立出来,采用关键字trait声明。
Scala中的trait中即可以有抽象属性和方法,也可以有具体的属性和方法,一个类可以混入(mixin)多个特质。这种感觉类似于Java中的抽象类。
Scala引入trait特征,第一可以替代Java的接口,第二个也是对单继承机制的一种补充。
1.特质声明
1)基本语法:
trait 特质名 {
抽象属性
非抽象属性
抽象方法
非抽象方法
}
2)通过查看字节码,可以看到特质 = 抽象类 + 接口
2.特质继承
一个类具有某种特质(特征),就意味着这个类满足了这个特质(特征)的所有要素,所以在使用时,也采用了extends关键字,如果有多个特质或存在父类,那么需要采用with关键字连接。
基本语法:
-
1)没有父类:
class 类名 extends 特质1 with 特质2 with 特质3 …
-
2)有父类:
class 类名 extends 父类 with 特质1 with 特质2 with 特质3…
说明:
- 1)类和特质的关系:使用继承的关系。
- 2)当一个类去继承特质时,第一个连接词是extends,后面是with
- 3)如果一个类在同时继承特质和父类时,应当把父类写在extends后
特点:
- 1)特质可以同时拥有抽象方法和具体方法
- 2)一个类可以混入(mixin)多个特质
- 3)所有的Java接口都可以当做Scala特质使用
- 4)动态混入:可灵活的扩展类的功能
- 4.1)动态混入:创建对象时混入trait,而无需使类混入该trait
- 4.2)如果混入的trait中有未实现的方法,则需要实现
trait PersonTrait {
//(1)特质可以同时拥有抽象方法和具体方法
// 声明属性
var name: String = _
// 抽象属性
var age: Int
// 声明方法
def eat(): Unit = {
println("eat")
}
// 抽象方法
def say(): Unit
}
trait SexTrait {
var sex: String
}
//(2)一个类可以实现/继承多个特质
//(3)所有的Java接口都可以当做Scala特质使用
class Teacher extends PersonTrait with java.io.Serializable {
//实现PersonTrait 的方法与属性
override def say(): Unit = {
println("say")
}
override var age: Int = _
}
object TestTrait {
def main(args: Array[String]): Unit = {
val teacher = new Teacher
teacher.say() //
teacher.eat() //
//(4)动态混入:可灵活的扩展类的功能
val t2 = new Teacher with SexTrait {
override var sex: String = "男"
}
//调用混入trait的属性
println(t2.sex)
}
}
3.特质叠加*
由于一个类可以混入(mixin)多个trait,且trait中可以有具体的属性和方法,若混入的特质中具有相同的方法(方法名,参数列表,返回值均相同),必然会出现继承冲突问题。冲突分为以下两种:
1)一个类(Sub)混入的两个trait(TraitA,TraitB)中具有相同的具体方法,且两个trait之间没有任何关系,解决这类冲突问题,直接在类(Sub)中重写冲突方法。
object TestTrait1 {
def main(args: Array[String]): Unit = {
val mc = new MyClass
mc.m1() //m1的实现
}
}
trait TraitA{
def m1():Unit={
println("TraitA m1")
}
}
trait TraitB{
def m1():Unit={
println("TraitB m1")
}
}
class MyClass extends TraitA with TraitB{
override def m1(): Unit = {
println("m1的实现")
}
}
2)一个类(Sub)混入的两个trait(TraitA,TraitB)中具有相同的具体方法,且两个trait继承自相同的trait(TraitC),及所谓的“钻石问题”,解决这类冲突问题,Scala采用了特质叠加的策略。
- 所谓的特质叠加,就是将混入的多个trait中的冲突方法叠加起来,案例如下:
trait Ball {
def describe(): String = {
"ball"
}
}
trait Color extends Ball {
override def describe(): String = {
"blue-" + super.describe()
}
}
trait Category extends Ball {
override def describe(): String = {
"foot-" + super.describe()
}
}
class MyBall extends Category with Color {
override def describe(): String = {
"my ball is a " + super.describe()
}
}
object TestTrait {
def main(args: Array[String]): Unit = {
println(new MyBall().describe())
//输出结果:my ball is a blue-foot-boot
}
}
4.特质叠加执行顺序
上述案例中的super.describe()是如何调父trait中的方法的?
当一个类混入多个特质的时候,scala会对所有的特质及其父特质按照一定的顺序进行排序,而此案例中的super.describe()调用的实际上是排好序后的下一个特质中的describe()方法。
排序规则如下:
结论:
- 1)案例中的super,不是表示其父特质对象,而是表示上述叠加顺序中的下一个特质,即,MyClass中的super指代Color,Color中的super指代Category,Category中的super指代Ball。
- 2)如果想要调用某个指定的混入特质中的方法,可以增加约束:super[],例如
super[Category].describe()
。
......
class MyBall extends Category with Color {
override def describe(): String = {
//1)任按照特质叠加顺序调用:输出结果与原结果一致
//"my ball is a " + super[Color].describe()
//2)直接调用某个指定的混入特质中的方法:不会按照原顺序去执行
"my ball is a " + super[Category].describe()
//输出结果:my ball is a foot-ball
}
}
object TestTrait {
def main(args: Array[String]): Unit = {
println(new MyBall().describe())
}
}
5.特质自身类型
特质自身类型:
- 1.实现了依赖注入的功能
- 2.要求混入该特质的同时,要混入特质自身类型
class User(val name: String, val age: Int)
//DAO层:和数据库打交道,完成数据的CRUD
trait Dao {
def insert(user: User) = {
println("insert into database :" + user.name)
}
}
//
trait APP {
//1.实现了依赖注入的功能
_: Dao =>
//可以注入多个:所有的java接口,都可以当做特质被混入
// _: Dao with Exeception =>
def login(user: User): Unit = {
println("login :" + user.name)
insert(user)
}
}
//2.要求混入该特质(如APP)的同时要混入特质自身类型(APP中存在特质自身类型Dao)
object MyApp extends APP with Dao {
def main(args: Array[String]): Unit = {
login(new User("bobo", 11))
}
}
6.特质和抽象类的区别
抽象类和特质关系:
1)抽象类中可以定义抽象属性、抽象方法、非抽象属性、非抽象方法
- 特质中也可以定义抽象属性、抽象方法、非抽象属性、非抽象方法
2)抽象类和特质都不能被实例化
- 抽象类有构造方法
- 特质也有构造方法
- 父类的构造方法调用就近原则(先继承谁先调用)
3)如果需要给构造方法传递参数的话,使用抽象类。因为抽象类可以定义带参数的构造函数,而特质不行(有无参构造)。
4)优先选择特质,scala是单继承,如果直接继承不方便后续的扩展
5)对大量对象的共性进行抽象—>类;对大量类共性进行抽象–>抽象类
- 而特质一般是对行为进行抽象,定义规范
- 一般的如果子父类满足 is-a 的原则,选择抽象类
object TestTraitAndAbstract {
def main(args: Array[String]): Unit = {
new MyClass
}
}
trait TraitA{
println("特质的构造方法")
def m1():Unit
}
abstract class MyAbstract{
println("抽象类的构造方法")
def m1():Unit
}
class MyClass extends MyAbstract with TraitA{
println("myclass 的构造方法")
override def m1(): Unit = {
println("myclass")
}
}
输出结果:
抽象类的构造方法
特质的构造方法
myclass 的构造方法
九.其他
1.类型检查和转换
(1)obj.isInstanceOf[T]
:判断obj是不是T类型。
(2)obj.asInstanceOf[T]
:将obj强转成T类型。
(3)classOf[T]
:获取对象的类名。
object TestInstanceOf {
def main(args: Array[String]): Unit = {
//创建一个Person23对象
val per:Any = new String
//判断per是否是Person23类型
val res: Boolean = per.isInstanceOf[Person23]
println(res)
if(res){
//将Any类型的对象per强转为Person23类型 注意:强转需要存在继承关系
val p1: Person23 = per.asInstanceOf[Person23]
}
//获取类型的信息
val clz: Class[Person23] = classOf[Person23]
println(clz)
}
}
class Person23{}
2.枚举类和应用类
说明:
- 枚举类:需要继承Enumeration
- 应用类:需要继承App
object TestEnum {
def main(args: Array[String]): Unit = {
println(Color.BLUE)
//输出:blue
}
}
// 枚举类:object修饰
object Color extends Enumeration {
val BLUE = Value(1,"blue")
val RED = Value(2,"red")
val GREEN = Value(3,"green")
}
// 应用类:其可以直接执行
object Test extends App {
println("xxxxxxxxxxx")
}
3.Type定义新类型
使用type关键字可以定义新的数据数据类型名称,本质上就是类型的一个别名。
object Test {
def main(args: Array[String]): Unit = {
//S本质就是String的别名
type S = String
var v:S = "abc"
def test():S = "xyz"
}
}