【Scala---03】Scala 类与对象 『 类 | 属性 | 访问权限 | 方法 | 继承 | 伴生对象&伴生类 | 查看类/对象的所有方法 | case』

文章详细介绍了Scala和Java中类的定义,包括属性的封装、访问权限控制、方法的定义、重载和重写,以及构造器的使用。同时,讨论了Scala中的可变参数和继承机制,并特别讲解了伴生对象和伴生类的概念及其在两门语言中的差异。
摘要由CSDN通过智能技术生成

1. 定义类

// Java 代码
public class Test {
	public static void main(String[] args){
		......
	}
}

// Scala代码
object Test {
	def main(args:Array[String]):Unit = {   
		......
	}
}

细节:

  1. Java文件:一个.java中可以有多个类,但是必须存在一个类用public修饰,并且用public修饰的类的 类名 必须 与 文件名 一样。

  2. Scala文件:一个.scala中可以包含多个类,且所有的类都不需要用public修饰,不要求 类名文件名一致。

    因为所有的类默认加上了public关键字,如果再写上public就重复了,反而就会报错

  3. .scala文件,需要先编译成.class文件才能运行。
    在这里插入图片描述

  4. 定义类名:以字母开头,后面接 字母、数字、下划线、$。在Scala中我一般采用首字母大写 + 下划线分隔,没有采用驼峰命名法。比如Search_c_video_na.scala

2. 属性

  • Java封装操作如下:

    1. 将属性进行私有化
    2. 提供一个公共的set方法,用于对属性赋值
    3. 提供一个公共的get方法,用于获取属性的值
  • 在scala中所有的属性,不管是用public还是private修饰,在底层都是private,并通过get方法(obj.field())set方法(obj.field_=(value))访问该属性。因此,那个修饰符只用于定义 访问权限 的,没有起到封装的效果(Java是借助修饰符达到封装的效果)。

  • 属性的定义:

    class Student{
        // 1. 类的属性一般用 var 修饰,因为一般要修改属性值
        // 2. 如果赋null值,用 _ 代替 null
        var name: String =  _
        // 3. 由于一些场景下Java框架要利用反射调用getXXX和setXXX方法,有时候为了和这些框架兼容,需要显示生成getXXX和setXXX方法
        //    如果需要显示的生成getter、setter方法,用 @BeanProperty 注解即可
        @BeanProperty
        var age: Int = _
    }
    
    class Student{
        def main(args: Array[String]): Unit = {
            val st =  new Student()
            st.age = 50
        }
    }
    

3. 访问权限

  1. private私有权限,只在类的内部和伴生对象中可用。
  2. protected为受保护权限,同类、子类可以访问,同包无法访问
  3. private[包名]为包访问权限,指定包名下的类可以访问
  4. 默认(什么都不写),就是public,任何类都可以访问

4. 方法

4.1 定义方法与调用

  1. 方法的定义:
    classobject 类名 {
    	def 方法名([变量:变量类型,变量:变量类型]):返回值类型 = {
    		方法体
    	}
    }
    
    比如:
    在这里插入图片描述

    注意:如果方法是递归方法,则必须指名方法的返回值类型,不能不写。

  2. 方法的调用:有两种方式
    object Test {
        def sayTwoParams(name:String, age:Int):Unit = {
            println(s"name = $name, age = $age")
        }
        
        def sayOneParams(name:String):Unit = {
            println(s"name = $name")
        }
        
        def main(args: Array[String]): Unit = {
            val name = "zhangsan"
            val age = 18
            // 1. 方式一:像Java一样通过.调用方法
            Test.sayTwoParams(name, age)
            // 2. 方式二:直接调用,省略.
            Test sayTwoParams(name,age)
            Test sayOneParams name     // 如果只有一个参数,那么小括号可以省略
        }
    }
    

4.2 方法重写

def关键字前加上override关键字:

class Person {
    def run(): Unit = {
        println("person run")
    }
    
}

class Student extends Person {
	// 在 def 关键字前加上 override 关键字。源码是下面这种格式
    override 
    def run():Unit = {
        println("student run")
    }
}

4.3 方法重载

不用加关键字,直接写

class Person {
    def run(): Unit = {
        println("person run")
    }
    
    def run(name: String): Unit  = {
        println(s"${name} run")
    }
}

4.4 构造方法

(1) 构造器定义

Scala的构造方法分为两类:

  1. 主构造器:必须有
  2. 辅助构造器:必须调用主构造器
    在这里插入图片描述
  1. 主构造器必须有,如果主构造器没有参数,则括号可以省略。如:
    class Person {
    	......
    }
    
  2. 主构造器的方法体在哪里???
    在这里插入图片描述
  3. 辅助构造方法不能直接构建对象,必须直接或者间接调用主构造方法
    在这里插入图片描述
  4. 构造器调用其他另外的构造器,要求被调用构造器必须提前声明。也就是说,存在代码的先后顺序。

(2) 构造器的参数列表

  1. 未用var或val修饰,这个参数就是一个局部变量,底层有属性的特性
  2. var修饰参数,作为类的成员属性,可以修改
  3. val修饰参数,作为类的成员属性,不能修改
package chapter06

object Test07_ConstructorArgs {
  def main(args: Array[String]): Unit = {
    val person0 = new Person("zhangsan",11,"男")

    println(person0.name)

    println(person0.age)

    println(person0.sex)
  }
}

// 主构造器参数 分为3类:
// 没有修饰符 : 作为构造方法中的传入参数使用
// val 修饰 : 会自动生产同名的属性 并且定义为val
// var 修饰 : 会自动生产同名的属性 并且定义为var
class Person (name1:String,val age:Int,var sex:String){
  	val name = name1
	//  val age = age
	//  var sex = sex
}

(3) 构造器私有化

实现单例模式时,需要将构造器私有化。那么如何将构造器私有化,直接在主构造器前上加上private关键字:

class Student private (var name: String, var sage: Int){

}

object Student {
    private var instance:Student = _
    def getInstance(name:String, age:Int): Student = {
        if (instance == null) {
            instance = new Student("zhang",  18)
            return instance
        }
        instance
    }
}

4.5 默认参数

  1. 定义方法时,在参数的类型后面加上='默认值',这个参数就就被赋予了默认参数。
    object Test {
        def main(args: Array[String]): Unit = {
            this.defaultParam()
        }
    
        def defaultParam(path: String = "/user/home"):
        Unit = {
            print(path)
        }
    }
    // 输出:/user/home
    

4.6 可变参数

  1. 定义方法时,在参数的类型后面加上*,这个参数就变成了可变参数。(可变参数需放在最后,否则报错
    object Main {
        def main(args: Array[String]): Unit = {
            def sum(x:Int*):Int = {  // 在参数x后加上 * ,则x变成了可变参数
                var value = 0
                for(i <- x)
                    value += i
                value
            }
            println(sum(1, 2, 3))  // 输出:6
        }
    }
    
  2. 传入可变参数时,如果参数是集合,可通过:_*的方式传入:
    object Test {
        def main(args: Array[String]): Unit = {
            def printAll(x:Int*):Unit = {
                x.foreach(println)
            }
    
            val list = List(1, 2, 3)
            printAll(list:_*)
        }
    }
    

4.7 查看类/对象的所有方法

在这里插入图片描述

5. 继承

Scala和Java一样都是单继承机制:
在这里插入图片描述

6. 伴生对象 & 伴生类

6.1 伴生对象的由来

在Java的类中,用 static 关键字修饰的内部类、方法、属性,可以通过类名访问。比如:

class Student{
	public static String school;
}
class Main {
	public static void main(String[] args) {
		System.out.printf(Student.school);  // 通过类名直接访问。
	}
}

这里的Student.school是通过类名来访问,并不是通过对象访问,Java号称面向对象,这里就相当与面向对象的理念冲突了。

所以,在Scala中,没有 static 关键字。为了实现与 static 关键字相同的功能,于是引入了伴生对象。

  • 问:删除static关键字容易,如何实现static关键字的功能呢?

  • 思路:static 修饰的就是当前类所共享的,而Student.school,中的Student应该是一个对象,而不是类。自然的想到为每个类创建第一个同名字的对象,然后将 static 修饰的东西都放入该对象中即可。

  • 例子:

    class Student(var name:String, var age:Int) {
    	// 定义与类相关的一些信息
        def printerInfo():Unit = {
            println(s"姓名:${name}, 年龄;${age}")
        }
    }
    
    object Student{
    	// 所有Student在同一所学校
        var school:String = "XXX高中"  
        
        // main方法本来应该用static修饰,所以应该写在这里
        def main(args: Array[String]): Unit = {
            var stu = new Student("张三", 18)
            stu.printerInfo()
        }
    }
    

6.2 伴生对象 & 伴生类

  1. 伴生对象用object关键字修饰,伴生类用class关键字修饰。

  2. 他俩的名字必须相同,

  3. 且必须放在同一个scala文件中。

    class Student{
    	....
    }
    object Student{
    	....
    }
    

因为伴生对象相当于是存放static的地方,所以所有类的对象共享伴生对象中的数据
伴生对象与伴生类可以相互访问对方中的数据

7. case 类

在这里插入图片描述

case class Person(name:String, age:Int)

object Test {
    def main(args: Array[String]): Unit = {
        val list: List[Person] = List(Person("zhangsan", 18), Person("wangwu", 20))
        list.foreach(println)
    }
}

在这里插入图片描述

8. 对象的复制

  1. 样例类使用copy()方法复制,普通类需要自己编写复制方法。

    case class Person(name: String, age: Int)
    
    val john = Person("John", 30)
    val johnCopy = john.copy()
    
  2. 对于RDD或DataSet里面的Row对象,可以使用fromSeq()方法复制。比如:

    import org.apache.spark.sql.Row
    
    val newDf = df.rdd.map { row =>
      if (row.getAs[String]("chuilei_type") == "1") {
        // 创建新的 Row,并复制原始 Row 的值
        val newRow = Row.fromSeq(row.toSeq)
        newRow
      } else {
        // 如果不满足条件,保持原始 Row 不变
        row
      }
    }.toDF()
    

    注意:这是浅复制,并不是深复制,如果 Row 包含对其他对象的引用,这些引用将被共享,而不是复制。

9. 异常

override def remove(n: Int, count: Int) {
  if (count < 0) throw new IllegalArgumentException("removing negative number of elements: " + count.toString)
  else if (count == 0) return  // Did nothing
  if (n < 0 || n > size0 - count) throw new IndexOutOfBoundsException("at " + n.toString + " deleting " + count.toString)
  copy(n + count, n, size0 - (n + count))
  reduceToSize(size0 - count)
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ElegantCodingWH

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

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

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

打赏作者

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

抵扣说明:

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

余额充值