09_Scala_OOP下_静态_伴生类_对象_嵌套类_投影屏蔽

举报
alexsully 发表于 2021/04/11 01:20:17 2021/04/11
【摘要】 无静态的概念(伴生对象中声明和调用) 伴生对象(def apply():Dog = new Dog() 内部类访问外部类的属性 方式1:外部类名.this.属性名 AlexOuterClass.this.name 方式2:别名的方式 sullyouter => var name = "alex" ; sullyouter.name 投影:AlexOuterClass#AlexInnerClass

Java中静态方法不通过对象调用,通过类对象调用,所以静态操作并不是面向对象

public class Alex_Static {
    public static void main(String[] args) {
        Alex.sayAlex();
    }}

//public static 返回值类型 方法名(参数列表) {方法体}
class Alex {
    public static  void  sayAlex(){
        System.out.println("sayAlex");
    }
}


Scala中静态的概念-伴生对象
Scala 无静态的概念, 使用伴生对象兼容Java 静态的概念,类的所有静态内容都在它的伴生对象中声明和调用

静态属性和静态方法

1 伴生对象采用object关键字声明,伴生对象中声明的全是 "逻辑静态"内容,可以通过伴生对象名称直接调用。
2 伴生对象对应的类称之为伴生类,伴生对象名称应该和伴生类名一致。
3 伴生对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问

4 逻辑的理解,伴生对象其实就是类的静态方法和成员的集合 (逻辑静态方法)
5 实际,scala并没有生成静态的内容,只不过是将伴生对象生成了一个新的类,实现属性和方法的调用。
6 底层,伴生对象实现静态特性是依赖于 public static final  MODULE$ 实现的。 
7 伴生对象的声明应该和伴生类的声明在同一个源码文件中(如果不在同一个文件中会运行错误!) 

8 如果 class A 独立存在,那么A就是一个类, 如果 object A 独立存在,那么A就是一个"静态"性质的对象[即类对象], 在 object A中声明的属性和方法可以通过 A.属性 和 A.方法 来实现调用
9 存在伴生类和伴生对象时,图标

object CountGame {
  def main(args: Array[String]): Unit = {
    val f1 = new Fish("white")
    val f2 = new Fish("black")
    val f3 = new Fish("golden")
    Fish.count_fish(f1)
    Fish.count_fish(f2)
    Fish.count_fish(f3)
    Fish.show_count()
  }

}
//说明
//1. 当在同一个文件中,有 class Fish 和 object Fish
//2. class Fish 称为伴生类,将非静态的内容写到该类中
//3. object Fish 称为伴生对象,将静态的内容写入到该对象(类)
//4. class Fish 编译后底层生成 Fish类 Fish.class
//5. object Fish 编译后底层生成 Fish$类 Fish$.class
//6. 对于伴生对象的内容,我们可以直接通过 Fish.属性 或者方法

//伴生类
class Fish(fname: String) {
  var name: String = fname
}

//伴生对象
object Fish {
  var total_sum: Int = 0

  def count_fish (f: Fish): Unit ={
    total_sum += 1
  }
  def show_count ():Unit ={println("总数鱼: " + total_sum)}
}


底层原理

伴生对象-apply方法
伴生对象中定义apply方法,可以实现: 类名(参数) 方式 来创建对象实例

object ApplyDemo01 {
  def main(args: Array[String]): Unit = {
    val dog1 = new Dog("姐夫")
    //在伴生对象中定义apply方法,可以实现: 类名(参数) 方式 来创建对象实例
    //使用apply方法来创建对象
    val dog2 = Dog("小姐夫") //自动  apply(pName: String)
    val dog3 = Dog() // 自动触发 apply()
    
    println("Dog2.name=" + dog2.name) //小姐夫
    println("Dog3.name=" + dog3.name) //匿名大姐夫
  }
}

//案例演示apply方法.
class Dog (pName:String) {
  var name: String = pName
}
object Dog  {
  //编写一个apply

  def apply(pName: String): Dog = new Dog(pName)
  def apply(): Dog = new Dog("匿名大姐夫")
}


Java中,类中五大成员: 属性 方法 构造器 内部类 代码块

Java 内部类 可以直接访问私有属性,并且可以体现类与类之间的包含关系

public class TestJava {
    public static void main(String[] args) {
        //Java内部类的分类
//        从定义在外部类的成员位置上来看,
//        1) 成员内部类(没用static修饰)
//        2) 静态内部类(使用static修饰)

        //创建一个外部类对象
        OuterClass outer1 = new OuterClass();
        //创建一个外部类对象
        OuterClass outer2 = new OuterClass();
        // 创建Java成员内部类
        // 说明在Java中,将成员内部类当做一个属性,因此使用下面的方式来创建 outer1.new InnerClass().
        OuterClass.InnerClass inner1 = outer1.new InnerClass();
        OuterClass.InnerClass inner2 = outer2.new InnerClass();

        //下面的方法调用说明在java中,内部类只和类型相关,也就是说,只要是
        //OuterClass.InnerClass 类型的对象就可以传给 形参 InnerClass ic
        inner1.test(inner2);
        inner2.test(inner1);

        // 创建Java静态内部类
        // 因为在java中静态内部类是和类相关的,使用 new OuterClass.StaticInnerClass()
        OuterClass.StaticInnerClass staticInner = new OuterClass.StaticInnerClass();
    }
}

class OuterClass { //外部类
    class InnerClass { //成员内部类
        public void test(InnerClass ic) {
            System.out.println(ic);
        }
    }

    static class StaticInnerClass { //静态内部类
    }
}

Scala中嵌套类 等价于 Java中的内部类

Scala嵌套类 的成员内部类和静态内部类
在内部类中访问外部类的属性
 通过外部类对象访问 :外部类名.this.属性名  
 通过外部类别名访问(推荐) :外部类名别名.属性名   

类型投影  作用:屏蔽外部对象对内部类对象的限制/影响

object AlexIOuterClassDemo {

  def main(args: Array[String]): Unit = {

    val outer1: AlexOuterClass = new AlexOuterClass();
    val outer2: AlexOuterClass = new AlexOuterClass();

    //在scala中,创建成员内部类的语法是
    //对象.内部类  的方式创建, 这里语法可以看出在scala中,默认情况下内部类实例和外部对象关联
    // outer1 outer2创建出来的内部类不是同一个类型
    val inner1 = new outer1.AlexInnerClass
    val inner2 = new outer2.AlexInnerClass

    //测试一下使用inner1 去调用 info()
    inner1.info()

    //在默认情况下,scala的内部类的实例和创建该内部类实例的外部对象关联.
    inner1.test_ori(inner1) // 必须是 inner1 outer1.AlexInnerClass
    inner2.test_ori(inner2) // 必须是 inner2 outer1.AlexInnerClass
    
    // 使用投影后 忽略了外部对象对内部对象的限制 AlexOuterClass#AlexInnerClass
    inner1.test(inner2)
    inner2.test(inner1)
    
    
    //创建静态内部类实例 通Java创建方式
    val staticInner = new AlexOuterClass.ScalaStaticInnerClass()

  }
}

//外部类 问外部类的属性的方法1 外部类名.this.属性
class AlexOuterClass {
  //定义两个属性
  var name = "alex"
  private var age = 35  // 私有属性

  class AlexInnerClass { //成员内部类,

    def info() = {
      // 方式1 :外部类访问外部类的属性:  使用外部类名.this.属性名
      //  AlexOuterClass.this 就相当于是 AlexOuterClass 这个外部类的一个实例,
      //  通过 AlexOuterClass.this 实例对象去访问 name 属性, 同时也可以访问 私有属性 age
      println("name = " + AlexOuterClass.this.name + " sal =" + AlexOuterClass.this.age) }


    //如果使用  外部类#内部类  表示忽略内部类的对象关系,等同于Java中内部类的语法操作
    //这里有一个方法,可以接受AlexIuterClass实例
    //下面的 AlexOuterClass#AlexIuterClass 类型投影的作用就是屏蔽 外部对象对内部类对象的限制/影响

    def test(obj: AlexOuterClass#AlexInnerClass): Unit = {
     println("使用了类型投影" + obj)
    }
    def test_ori(obj: AlexInnerClass): Unit = {
      println("不使用了类型投影 会锁定外部对象" + obj)
    }
  }}

//方式2 :外部类访问外部类的属性 使用别名的方式
//1. 将外部类属性,写在别名后面
class SullyOuterClass {
  sullyouter => //这里我们可以这里理解 外部类的别名 看做是外部类的一个实例
  //定义两个属性
  var name = "alex"
  private var age = 35

  class SullyIuterClass { //成员内部类,
    def info() = {
      // 访问方式:外部类别名.属性名
      println("name~ = " + sullyouter.name + " sal~ =" + sullyouter.age) }

  }}

object AlexOuterClass { //伴生对象
  class ScalaStaticInnerClass { //静态内部类
  }}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。