对象一词在Java中代表着类的实例,在scala中有着双重含义,即表示类的实例又是一个关键词object
一 将对象视为类的实例
1.1对象的强制转换
可以使用asInstanceOf,这种情况一般适用于动态类型的强制转换
# 检测某个变量是否属于某一类型
变量.isInstanceOf[类型]
# 类型转换:变量.asInstanceOf[类型]
# 检测某一个变量的class是否属于某一个某一个类
变量.getClass ==classOf[类型]
classAnimal(var name:String,var age:Int) {
def this(name:String){
this(name,0)
}
def desc(): Unit ={
print(s"My name is$name, and my age is$age ")
}
}
class Lion(name:String, age:Int, var kind:String) extends Animal(name,age){
override def desc(): Unit = {
super.desc();
println("我是"+kind+"动物")
}
}
class Wolf(name:String, age:Int, var kind:String) extends Animal(name,age){
override def desc(): Unit = {
super.desc();
println("我是"+kind+"动物")
}
}
object ClassClient {
def main (args: Array[String]): Unit = {
val a:Animal = new Animal("小黄",12)
val lion:Animal = new Lion("马沙",5,"猫科")
val wolf:Wolf = new Wolf("西北",2,"犬科")
println(a.isInstanceOf[Animal])
println(lion.isInstanceOf[Animal])
println(wolf.isInstanceOf[Wolf])
if (lion.isInstanceOf[Animal]) {
val l = lion.asInstanceOf[Lion]
print(l.desc())
}
print(lion.getClass,classOf[Animal])
if (lion.getClass == classOf[Animal]){
println("true")
}
}
}
1.2Java.Class的Scala等价类
当API要求传入一个类,在Java中需要传入Java的.Class,但是在scala中不是这样做的。是通过传入classOf[类型]
valinfo = new DataLine.Info(classOf[Target
DataLine])
1.3 确定对象所属的类
变量.getClass
二 将对象视为object关键词(伴生对象)
2.1 用object启动一个应用
用main方法启动一个应用或者为脚本提供一个入口
我们可以用2种方式来解决这个问题:
第一种办法:定义object去继承App
object BasisObject extends App {
val numList = List(11,22,33,44,55)
numList.map((x:Int) => x - 1).foreach(e => print(e+" "))
}
第二种办法:定义一个object,手动实现一个main方法,类似于java
object BasisObject {
def main(args: Array[String]) {
val numList = List(11,22,33,44,55)
numList.map((x:Int) => x - 1).foreach(e => print(e+" "))
}
}
2.2 用object创建单例
创建一个单例对象,以保证只有一个类的实例存在
object CashRegister {
def open {println("opened")}
def closed {println("closed")}
}
然后CashRegister被定义为一个对象,他只能有一个实例,而且他的调用方式和java静态类有点类似
CashRegister.open
CashRegister.closed
这种模式在创建工具方法时
2.3 用伴生类创建静态成员
创建包含实例方法和静态方法的类,和java不一样scala没有静态关键字
在类中定义费静态成员,然后在伴生对象(和类名同名的object)中创建静态成员对象
class Pizza(var crustType:String) {
var price:Float = 0.0f;
def func(): Unit ={
println("披萨价格是=> "+price)
}
}
object Pizza{
val CRUST_TYPE_THIN = "thin";
val CRUST_TYPE_THICK = "thick"
defgetFoo = "Foo"
}
object BasisObject {
def main(args: Array[String]) {
/*我们空间又直接访问Pizza的静态成员*/
println(Pizza.CRUST_TYPE_THIN,Pizza.getFoo)
/*我们也可以创建对象*/
val p = new Pizza(Pizza.CRUST_TYPE_THICK)
p.price = 28.95f;
p.func()
}
}
访问私有成员变量:
知道类和其伴生类能互相访问私有成员很重要,
class Foo {
private val secret = 2;
}
object Foo{
def double(foo:Foo) = foo.secret * 2
}
object BasisObject {
def main(args: Array[String]) {
val foo = new Foo
print(Foo.double(foo))
}
}
class Foo {
private val secret = 2;
def printObj:Unit= {
println(s"I can see ${Foo.obj}")
}
}
object Foo{
private val obj = "Foo's Object"
def double(foo:Foo) = foo.secret * 2
}
object BasisObject {
def main(args: Array[String]) {
val foo = new Foo
foo.printObj
}
}
2.4 将通用代码放入包对象
在不引入类或者对象的前提下,让函数、字段或者其他代码在包级别可用
解决办法:
将要在所有类中共享的代码放在一个包中的对象中
大概就是:将很多类需要用到的代码,字段或者函数放入包中某一个object,然后包下的其他类或者object来调用这个object就不需要import
比如现在有一个包com.scala.objects.Tools包,这个包下面专门放一些工具方法
然后现在定一个包级别的(com.scala.objects.Tools)也就是跟包平级的一个object,名字必须与包名相同,所以这个object名字也叫Tools,然后这个object和com.scala.objects.Tools属于同一层级。
语法:package object 包名
package com.scala.objects
package object Tools {
//公用字段
val MAGIN_NUM = 42
//公用方法
def echo(a:Any){println(a.toString)}
//枚举
object Margin extends Enumeration{
type Margin = Value
val TOP,BOTTOM,LEFT,RIGHT = Value
}
//type
type MutableMap[K,V] = scala.collection.mutable.Map[K,V]
val MutableMap = scala.collection.mutable.Map
}
package com.scala.objects.Tools
object MainDriver extends App {
echo("Hello World")
echo(MAGIN_NUM)
echo(Margin.LEFT)
val mm = MutableMap("name"->"nicky")
mm += ("age"->"20")
for((k,v) <- mm) {
printf("key: %s, value: %s\n",k,v)
}
}
2.5 不使用new关键字创建对象实例
两种办法:
第一种:定义case class 类名,它在内部会自己创建apply方法,我们就可以不用new
case class People(name:String, var age:Int) {
def func(): Unit ={
println(name,age)
}
}
第二种:为类创建伴生对象,然后在伴生对象,我们自己提供apply方法
class Pizza(var crustType:String) {
var price:Float = 0.0f;
def func(): Unit ={
println("披萨价格是=> "+price)
}
}
object Pizza{
val CRUST_TYPE_THIN = "thin";
val CRUST_TYPE_THICK = "thick"
def getFoo = "Foo"
def apply(crustType:String):Pizza = {
val p = new Pizza(crustType)
p
}
}
其实内部也还是使用new去创建
2.6 在scala中用apply方法实现工厂方法
在scala中实现工厂方法,让子类声明哪一种对象应该被创建
我们可以利用半生对象的apply方法,与其为了工厂创建get方法,不如将工厂的决策算法放在apply方法内
需求:创建Animal 工厂,返回Cat和Dog的实例
abstract class Pet(name:String, age:Int) {
/*定义抽象属性,子类来实现*/
val greeting:String
var color:String
def sayHello{println(greeting)}
/*定义抽象方法,子类来实现*/
def action
override def toString:String = s"I say: $greeting, and I'm $age, my color is $color"
}
object Pet {
def apply(kind:String):Pet = {
if ("cat".equals(kind)) {
new Cat("小花", 2)
} else {
new Dog("小白", 3)
}
}
}
class Dog(name:String,age:Int) extends Pet(name,age){
val greeting = "汪汪"
var color = "白色"
override def action: Unit = {
print("我正在啃骨头")
}
}
class Cat(name:String, age:Int) extends Pet(name,age){
val greeting = "喵喵"
var color = "黑色"
override def action: Unit = {
print("我正在卖萌")
}
}
object ClassClient {
def main(args: Array[String]) {
val dog = Pet("dog")
val cat = Pet("cat")
println(dog.sayHello)
println(cat.sayHello)
}
}