Scala面向对象编程-封装、继承


面向对象三大特征:封装、继承和多态

封装

封装的好处
1)隐藏实现细节
2)可以对数据进行验证,保证数据安全合理
3)封装的同时可以加入业务逻辑
封装的步骤
1)属性私有化
2)提供公共的 get set 方法 用于赋值和读取值

注意事项

1)Scala中为了简化代码开发,当属性声明为 var【非private】时会自动生成 public 的 xxx 和 xxx$seq方法, 但是如果属性声明为private 那么这两个方法也会变成private .
因此 一般情况下 我们只是对一个属性简单的set 和get 那么 只需要声明非private 的var属性即可。
2)从形式上看如果 p.name 是直接访问的属性,但实际上是调用的 name方法
3)因为上述特性 很多框架在进行反射时,支持对属性的直接反射
4)BeanProperty 注解不能用于 private属性
示例:

class Person{
       var name:String=_
       private var age:Int=_
       //@BeanProperty  //BeanProperty 注解不能用于 private属性
       private var salary:Float=_
       def getAge:Int={
         return this.age
       }
       def setAge(age:Int)={
         if(age>120){
           this.age=120;
         }else if(age<0){
           this.age=0
         }else{
           this.age=age
         }
       }
    }

调用示例:

 def test={
      var p = new Person()
      p.setAge(1000)
      println(p.getAge)
    }

示例反编译结果(底层实现):

public class class06$Person
{
  private String name;
  private int age;

  public String name()
  {
    return this.name; }
  public void name_$eq(String x$1) { this.name = x$1; }
  private int age() { return this.age; }
  private void age_$eq(int x$1) { this.age = x$1; }

  public int getAge() { return age(); }

  public void setAge(int age) {
    if (age > 120)
      age_$eq(120);
    else if (age < 0)
      age_$eq(0);
    else
      age_$eq(age);
  }
}

继承

继承可以提高代码复用性、扩展性及可维护性
java 中的继承实现方式
class 子类名 extends 父类名{} 子类继承父类的 属性和方法
scala 中继承语法 和 java相似,子类继承了父类的所有属性,只是私有属性不能直接访问,需要通过公共的方法去访问。

方法重写

scala明确规定,重写一个非抽象方法需要使用override修饰符,重写时可以通过super关键字调用父类的方法
示例如下:

 class Base{
    var n1:Int=1;
    protected var n2:Int=2;
    private var n3:Int=3;

    def f1={
      println("基类-----f1")
    }
    protected def f2={
      println("基类-----f2")
    }
    private def f3={
      println("基类-----f3")
    }
  }
  class Sub extends Base{
    override def f1: Unit = {
      super.f1
      println("子类==========f1")
    }
    def showInfo={
      println("修改前:n1="+n1+" n2="+n2+" n3=")//n3 无法访问
      this.n1=10
      this.n2=20
      //this.n3 //n3无法直接访问
      println("修改后:n1="+n1+" n2="+n2+" n3=")
      f1
      f2
      //f3 //f3 无法访问
    }
  }

调用

  def test={
   var s=new Sub
    s.showInfo
  }

覆写字段

scala 中子类改写父类的字段 我们称之为 覆写字段。 java 中只有方法的重写没有字段的重写(准确讲是隐藏字段代替重写)
( java 中为什么不能重写字段?)

java 中动态绑定机制

1)如果调用的是方法,那么jvm会将方法和对象的内存地址绑定
2)如果调用的是属性,则没有动态绑定机制,在哪里调用就返回哪里的值
示例

class AA {
    public int i =10;
    public String flag ="父类";
    public int sum1(){
        return (getI()+10);
    }
    public int sum(){
        return (i+10);
    }
    public int getI() {
        return i;
    }
    public void setI(int i) {
        this.i = i;
    }
}
class BB extends  AA{
    public int i=20;
    public int getI() {
        return i;
    }
    public void setI(int i) {
        this.i = i;
    }
    public String getFlag(){
        return this.flag;
    }
}
  public static void main(String[] args) {
        //将一个子类的对象地址,交给一个AA 父类的引用
        //如果调用的是方法,则jvm 会吧方法和 对象的内存绑定
        //如果是调用属性,没有动态绑定机制,在哪里调用就返回哪里的值
         AA a = new BB();
        BB b = new BB();
        System.out.println(a.i);//输出  10
        System.out.println(b.i);//输出  20
         System.out.println(a.sum());//输出  20
        System.out.println(a.sum1());//输出 30
    }

scala覆写字段注意事项

1)def只能重写另一个def(方法只能重写另一个方法)
2)val 只能重写另一个val属性 或者重写不带参数的def
3) var 只能重写另一个抽象的var属性
*一个属性没有初始化,那么这个属性就是个抽象属性(只能存在于抽象类中)
*抽象属性在编译成字节码文件时,属性并不会声明,但是会自动生成抽象的属性操作方法
*如果是腹泻一个父类的抽象属性,override关键字可以省略
示例:

abstract class AA{
  val age:Int =10;
  var name:String ="AA"
  def sal():Int={
    return 10;
  }
  var sex:String
}
class BB extends AA{
  override val age:Int =20;
  //override var name:String ="BB"//var 属性重写是 执行会报错 提示补鞥呢重写var属性
  override val sal:Int=30;//由于scala会自动生成 sal()方法,该方法会覆盖 父类中的 sal方法
  var sex:String="男"
}
  def test={
    var a:AA = new BB()
    var b:BB = new BB()
    //可以看到和java的不同 感觉父类的属性被覆盖了
    //原理就是 我们这里调用属性 在底层都是调用子类的java 方法 ,由于java的动态绑定机制,所以都返回的 子类的值
    println("a.age="+a.age+"   b.age="+b.age)//a.age=20   b.age=20
    println("a.name="+a.name+"   b.name="+b.name)// a.name=AA   b.name=AA
    println("a.sal="+a.sal+"   b.sal="+b.sal)//a.sal=30   b.sal=30
    println("a.sex="+a.sex+"   b.sex="+b.sex)//a.sex=男   b.sex=男
  }

抽象类

scala中通过abstract关键字标记不能被实例化的类。抽象方法不用abstract标记,只要省略方法体即可
抽象类可以拥有抽象字段(没有被初始化的字段)

注意事项

1)抽象类不能被示例化,默认情况下不允许实例化抽象类,
但是如果实例化时动态实现抽象类的所有先后向方法也可以.(这种情况下实际上是创建了匿名子类实例)
2)抽象类不一定包含抽象方法和抽象属性
3)一旦类重有抽象方法或抽象属性 那么类必须是抽象的
4)如果一个类继承了抽象类,那么它必须实现所有的抽象方法和属性,除非他自己也是抽象类
5)抽象方法一定不能使用 abstract 修饰否则执行报错
6)抽象方法不能使用 private final 修饰,因为这些关键字和重写相违背
7)抽象类中可以有 已完成实现的方法
8)子类重写抽象方法可以不加 override 加了也不报错
示例:


abstract class Animal{
    var name:String
    //final var age:Int //会提示final 不能用于未实现的属性
    var color:String="黑"
    def cry()
    //abstract def eat()  //抽象方法不能使用 abstract 修饰
  }
 def test: Unit ={
   var  a1:Animal = new Animal {
     override var name: String = _
     override def cry(): Unit = {
       println("  a1")
     }
   }
   var  a2:Animal = new Animal {
     override var name: String = _
     override def cry(): Unit = {
       println("  a2")
     }
   }
   a1.cry()
   a2.cry()
 }

scala中的类型检查和转换

scala 中的类型检查和转换
classOf[String] 相当于java 中的 String.class 返回对象类型
obj.isInstanceOf[T] 相当于 java中的 obj instanceof T 判断对象是否为T类型
obj.asInstanceOf[T] 相当于java中的(T)obj 强制将obj转换为T 类型

示例:

    class Person{
    var name:String ="tom"
    def printName={
      println("Person print name " + name)
    }

  }
  class Emp extends Person{
    override def printName={
      println("Emp print name " + name)
      super.printName
    }

  }
  def test={
   var p:Person = new Emp
    println(classOf[Person])
    println(p.getClass.getName)
    if(p.isInstanceOf[Emp]){
        var p2:Emp = p.asInstanceOf[Emp]
        p2.printName
    }
  }

输出结果:

  class com.test.class06$Person
com.test.class06$Emp
Emp print name tom
Person print name tom

构造器说明

构造器说明:
1)每个类有一个主构造器和任意多个辅助构造器,且每个辅助构造器必须先调用主构造器
2)只有主构造器才可以调用父类构造器,辅助构造器不能直接调用父类构造器
测试

class Base {
     var name:String=_;
     def this(inName:String){
       this
       println("base 辅助构造器"+inName)
     }
     println("Base 主构造器"+name)
   }
   class Sub(inName:String ,inAge:Int) extends  Base(inName){// 对 父类构造的调用应该是在这行定义的 这里
     //super(inName) 在子类中不能通过这种形式调用父类构造
     println("SUb 主构造器"+name)
     def this(){
       this("张三",19);
       println("SUb 辅助构造器" +name)
     }
     def this(name:String){
       this(name,19);
       println("SUb 辅助构造器"+name)
     }
   }
  def test={
    new Sub("tom")
  }

输出结果:

 Base 主构造器null
base 辅助构造器tom
SUb 主构造器null
SUb 辅助构造器tom
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

catch that elf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值