提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、Scala数据类型
1.各数据类型描述
2.使用细节
2.1 整型、浮点型、字符型
2.2 Unit、Null、Nothing类型
//Null类只有一个实例对象null,类似于java中的null引用,null可以赋值给任意引用类型AnyRef,但是不能赋值给值类型AnyVal
//Unit类型用来标识过程,也就是没用明确返回值的函数,类似于java里的void。Unit类只有一个实例(),没有实质意义。
def sayOk(): Unit = {
println("ok")
}
//Nothing类可以作为没有正常返回值的方法的返回类型,非常直观的告诉你这个方法不会正常返回。该类是其他任意类型的子类,可以跟要求返回值的方法兼容。
def test() : Nothing = {
throw new Exception()
}
二、Scala类
1.类与对象
1.1 属性/成员变量
package scalaDemo
object NullType {
def main(args: Array[String]): Unit = {
val cat = new Cat
println(
s"出生地:${cat.birthPlace}\n性别:${cat.gender}\n年龄:${cat.age}\n体重:${cat.height}\n是否可爱:${cat.isLovely}"
)
}
}
class Cat {
var name: String = "狸花猫"
var color: String = null
var birthPlace = null //Null类型,null为Null的一个实例
var gender: String = _ //字符串类型默认值 null
var age: Int = _ //Int类型默认值 0
var height: Double = _ //Double类型默认值 0.0
var isLovely: Boolean = _ //布尔类型默认值 false
}
1.2 对象的内存布局
1.3 方法和函数
程序调用方法过程
1.4 构造器
说明:
1.主构造器只有1个,辅助构造器方法名为this,可以有多个,编译器通过不同的参数类型来区分
package scalaDemo
object ConstractParam {
def main(args: Array[String]): Unit = {
val s = new Student2("sunny", "male", 28,172)
println(s"${s.name}\n${s.gender}\n${s.age}")
}
}
//1 主构造器的形参未加修饰符,这个参数为局部变量
//2 val修饰,这个参数会作为类的私有属性,只能读取
//3 var修饰,这个参数会作为类的私有属性,既能读取又能赋值
class Student2(inName: String, val inGender: String, var inAge: Int, inHeight: Double) {
val name: String = inName
val gender: String = inGender
var age: Int = inAge
var height: Double = _
}
反编译代码:
package scalaDemo;
import scala.reflect.ScalaSignature;
@ScalaSignature(bytes = "\006\001E3A!\001\002\001\013\tA1\013^;eK:$(GC\001\004\003%\0318-\0317b\t\026lwn\001\001\024\005\0011\001CA\004\013\033\005A!\"A\005\002\013M\034\027\r\\1\n\005-A!AB!osJ+g\r\003\005\016\001\t\005\t\025!\003\017\003\031IgNT1nKB\021qB\005\b\003\017AI!!\005\005\002\rA\023X\rZ3g\023\t\031BC\001\004TiJLgn\032\006\003#!A\001B\006\001\003\006\004%\taF\001\tS:<UM\0343feV\ta\002\003\005\032\001\t\005\t\025!\003\017\003%IgnR3oI\026\024\b\005\003\005\034\001\t\005\r\021\"\001\035\003\025Ig.Q4f+\005i\002CA\004\037\023\ty\002BA\002J]RD\001\"\t\001\003\002\004%\tAI\001\nS:\fu-Z0%KF$\"a\t\024\021\005\035!\023BA\023\t\005\021)f.\033;\t\017\035\002\023\021!a\001;\005\031\001\020J\031\t\021%\002!\021!Q!\nu\ta!\0338BO\026\004\003\002C\026\001\005\003\005\013\021\002\027\002\021%t\007*Z5hQR\004\"aB\027\n\0059B!A\002#pk\ndW\rC\0031\001\021\005\021'\001\004=S:LGO\020\013\006eQ*dg\016\t\003g\001i\021A\001\005\006\033=\002\rA\004\005\006-=\002\rA\004\005\0067=\002\r!\b\005\006W=\002\r\001\f\005\bs\001\021\r\021\"\001\030\003\021q\027-\\3\t\rm\002\001\025!\003\017\003\025q\027-\\3!\021\035i\004A1A\005\002]\taaZ3oI\026\024\bBB \001A\003%a\"A\004hK:$WM\035\021\t\017\005\003\001\031!C\0019\005\031\021mZ3\t\017\r\003\001\031!C\001\t\0069\021mZ3`I\025\fHCA\022F\021\0359#)!AA\002uAaa\022\001!B\023i\022\001B1hK\002B\021\"\023\001A\002\003\007I\021\001&\002\r!,\027n\0325u+\005a\003\"\003'\001\001\004\005\r\021\"\001N\003)AW-[4ii~#S-\035\013\003G9CqaJ&\002\002\003\007A\006\003\004Q\001\001\006K\001L\001\bQ\026Lw\r\033;!\001")
public class Student2 {
private final String inGender;
private int inAge;
private final String name;
private final String gender;
private int age;
private double height;
public String inGender() {
return this.inGender;
}
public int inAge() {
return this.inAge;
}
public void inAge_$eq(int x$1) {
this.inAge = x$1;
}
public Student2(String inName, String inGender, int inAge, double inHeight) {
this.name = inName;
this.gender = inGender;
this.age = inAge();
}
public String name() {
return this.name;
}
public String gender() {
return this.gender;
}
public int age() {
return this.age;
}
public void age_$eq(int x$1) {
this.age = x$1;
}
public double height() {
return this.height;
}
public void height_$eq(double x$1) {
this.height = x$1;
}
}
1.5 对象创建流程
1.6 scala包
package scalaDemo
object CompanionObject {
def main(args: Array[String]): Unit = {
val person = new Person()
val student = new Student
person.name = "鞠婧祎" //person.name_$eq("鞠婧祎")
person.gender2 = "女" //person.gender_$eq("女")
// person.age = 26 //person.age_$eq(26)
println(classOf[Person])
println(person.getClass.getName)
}
}
class Person {
private val privateDescription: String = "私有属性-人类" //生成的字节码文件中,只有私有的getter方法--pirvate String privateDescription()
val publicDescription: String = "公有属性-动物" //生成的字节码文件中,只有公有的getter方法--public String publicDescription()
var name: String = _ //var修饰的变量,编译成的字节码文件中,既有setter方法又有getter方法
protected var gender1: String = _ //当前类及其子类对象可以访问
protected[scalaDemo] var gender2: String = _ //String和引用类型的变量,使用"_"初始化时全部为null
private var age: Int = _ //val修饰的属性,字节码文件只有getter方法,而var修饰的属性,字节码文件既有setter又有getter方法
println(Person.height) //访问伴生对象的私有属性--直接类名访问
}
object Person {
private var height: Double = _
private val person = new Person
person.age //访问伴生类私有属性,需要先new一个对象
//Person.age //无法通过类名访问
}
class Student extends Person {
private val person = new Person //子类中无法继承父类中的私有属性
}
/*
public class Person {
private final String privateDescription = ";
private String privateDescription() {
return this.privateDescription;
}
private final String publicDescription = ";
private String name;
private String gender;
private int age;
public String publicDescription() {
return this.publicDescription;
}
public String name() {
return this.name;
}
public void name_$eq(String x$1) {
this.name = x$1;
}
public String gender() {
return this.gender;
}
public void gender_$eq(String x$1) {
this.gender = x$1;
}
private int age() {
return this.age;
}
private void age_$eq(int x$1) {
this.age = x$1;
}
}
*/
2.类的继承
2.1 成员变量和成员方法的继承
package scalaDemo.extendsDemo.demo03
object ExtendsRelation {
def main(args: Array[String]): Unit = {
val son01 = new Son01
val grandSon01 = new GrandSon01
son01.sonInfo
grandSon01.grandSonInfo
}
}
//1.在scala中,子类继承了父类所有属性,但是private修饰的属性和方法在子类中无法访问,只能在本类和伴生对象中使用
//2.protected修饰的属性和方法在子类中可以访问
//3.protected,private修饰的除了上述位置,不能在同包的其他位置被访问
class Father01 {
var name: String = "Lucy"
protected var gender: String = "female"
private var age: Int = 18
def getBaseInfo = {
println(s"name=$name gender=$gender age=$age")
}
protected def getJobInfo = {
println("this is protected info...")
}
private def getSalaryInfo = {
println("this is private info...")
}
}
class Son01 extends Father01 {
def sonInfo = {
this.name = "LucySon01" //可访问--this.name_$eq("LucySon01")
this.gender = "male" //可访问--this.gender_$eq("LucySon01")
// this.age = 0 --无法访问
println(s"Son01: ${this.name} ${this.gender}")
}
}
class GrandSon01 extends Son01 {
def grandSonInfo = {
this.name = "LucyGrandSon01"
this.gender = "male"
// this.age = 0 --无法访问
println(s"GrandSon01: ${this.name} ${this.gender}")
}
}
2.2 重写方法
package scalaDemo.extendsDemo.demo03
object OverrideMethod {
def main(args: Array[String]): Unit = {
val son02 = new Son02
son02.getInfo
}
}
class Father02 {
var name: String = "Lucy"
def getInfo = {
println(s"Father==$name")
}
def sayHello = {
println("hello~~~")
}
}
class Son02 extends Father02 {
override def getInfo: Unit = {
println(s"Son==$name")
//子类中调用父类被重写的方法,使用supper
super.getInfo
//如果方法没有被重写,在子类中直接调用
sayHello
}
}
2.3 类型检查和转换
package scalaDemo.extendsDemo.demo03
object TypeConvert {
def main(args: Array[String]): Unit = {
val s1 = new Son03
val s2 = new Son033
convert(s1)
convert(s2)
}
//父类的引用可以接收所有子类的引用--多态
def convert(fa: Father03) = {
if (fa.isInstanceOf[Son03]) {
val son = fa.asInstanceOf[Son03]
son.sonMethod
} else if (fa.isInstanceOf[Son033]) {
val son = fa.asInstanceOf[Son033]
son.sonMethod
} else {
println(s"类型转换失败==${fa.getClass}")
}
}
}
class Father03 {
val name = "father"
def baseInfo = {
println(s"name is $name")
}
def fatherMethod = {
println(s"method is $name")
}
}
class Son03 extends Father03 {
val son03Name = "son03"
override def baseInfo: Unit = {
println(s"sonName is $son03Name")
}
def sonMethod = {
println(s"method is $son03Name")
}
}
class Son033 extends Father03 {
val son033Name = "son033"
override def baseInfo: Unit = {
println(s"sonName is $son033Name")
}
def sonMethod = {
println(s"method is $son033Name")
}
}
2.4 超类的构造
package scalaDemo.extendsDemo.demo03
object Constructor {
def main(args: Array[String]): Unit = {
/**
* 执行流程:
* 1.先调用子类辅助构造器this(height: Double)
* 2.调用this即子类的主构造器,但是在初始化子类属性之前,必须先调用父类的主构造器
* 3.调用父类this()即子类的辅助构造器,然后this("Lucy")即父类的主构造器
* 4.输出结果
* 父类-主构造器1...
* 父类-主构造器2...
* 父类-辅助构造器3...
* 子类-主构造器1...
* 子类-主构造器2...
* 子类-辅助构造器...
**/
val son04 = new Son04(172)
}
}
class Father04(inName: String) {
var name: String = inName
var age: Int = _
var gender: String = _
println("父类-主构造器1...")
def this(inName: String, inAge: Int) = {
this(inName)
this.age = inAge //实际调用age_$eq(inAge);
println("父类-辅助构造器1...")
}
def this(inName: String, inAge: Int, inGender: String) = {
this(inName, inAge)
this.gender = inGender //实际调用gender_$eq(inGender);
println("父类-辅助构造器2...")
}
println("父类-主构造器2...")
def this() = {
this("Lucy") //调用主构造器
println("父类-辅助构造器3...")
}
}
class Son04() extends Father04() {
var height: Double = _
println("子类-主构造器1...")
def this(height: Double) = {
this
this.height = height
println("子类-辅助构造器...")
}
println("子类-主构造器2...")
}
反编译代码:
package scalaDemo.extendsDemo.demo03;
import scala.Predef$;
import scala.reflect.ScalaSignature;
@ScalaSignature(bytes = "\006\001!2A!\001\002\001\023\t)1k\03481i)\0211\001B\001\007I\026lw\016M\032\013\005\0251\021aC3yi\026tGm\035#f[>T\021aB\001\ng\016\fG.\031#f[>\034\001a\005\002\001\025A\0211\002D\007\002\005%\021QB\001\002\t\r\006$\b.\032:1i!)q\002\001C\001!\0051A(\0338jiz\"\022!\005\t\003\027\001A\021b\005\001A\002\003\007I\021\001\013\002\r!,\027n\0325u+\005)\002C\001\f\032\033\0059\"\"\001\r\002\013M\034\027\r\\1\n\005i9\"A\002#pk\ndW\rC\005\035\001\001\007\t\031!C\001;\005Q\001.Z5hQR|F%Z9\025\005y\t\003C\001\f \023\t\001sC\001\003V]&$\bb\002\022\034\003\003\005\r!F\001\004q\022\n\004B\002\023\001A\003&Q#A\004iK&<\007\016\036\021\t\013=\001A\021\001\024\025\005E9\003\"B\n&\001\004)\002")
public class Son04 extends Father04 {
private double height;
public Son04() {
Predef$.MODULE$.println(");
Predef$.MODULE$.println(");
}
public double height() {
return this.height;
}
public void height_$eq(double x$1) {
this.height = x$1;
}
public Son04(double height) {
this();
height_$eq(height);
Predef$.MODULE$.println(");
}
}
package scalaDemo.extendsDemo.demo03;
import scala.Predef$;
import scala.reflect.ScalaSignature;
@ScalaSignature(bytes = "\006\00153A!\001\002\001\023\tAa)\031;iKJ\004DG\003\002\004\t\0051A-Z7paMR!!\002\004\002\027\025DH/\0328eg\022+Wn\034\006\002\017\005I1oY1mC\022+Wn\\\002\001'\t\001!\002\005\002\f\0355\tABC\001\016\003\025\0318-\0317b\023\tyAB\001\004B]f\024VM\032\005\t#\001\021\t\021)A\005%\0051\021N\034(b[\026\004\"a\005\f\017\005-!\022BA\013\r\003\031\001&/\0323fM&\021q\003\007\002\007'R\024\030N\\4\013\005Ua\001\"\002\016\001\t\003Y\022A\002\037j]&$h\b\006\002\035=A\021Q\004A\007\002\005!)\021#\007a\001%!9\001\005\001a\001\n\003\t\023\001\0028b[\026,\022A\005\005\bG\001\001\r\021\"\001%\003!q\027-\\3`I\025\fHCA\023)!\tYa%\003\002(\031\t!QK\\5u\021\035I#%!AA\002I\t1\001\037\0232\021\031Y\003\001)Q\005%\005)a.Y7fA!IQ\006\001a\001\002\004%\tAL\001\004C\036,W#A\030\021\005-\001\024BA\031\r\005\rIe\016\036\005\ng\001\001\r\0211A\005\002Q\nq!Y4f?\022*\027\017\006\002&k!9\021FMA\001\002\004y\003BB\034\001A\003&q&\001\003bO\026\004\003\"C\035\001\001\004\005\r\021\"\001\"\003\0319WM\0343fe\"I1\b\001a\001\002\004%\t\001P\001\013O\026tG-\032:`I\025\fHCA\023>\021\035I#(!AA\002IAaa\020\001!B\023\021\022aB4f]\022,'\017\t\005\0065\001!\t!\021\013\0049\t\033\005\"B\tA\001\004\021\002\"\002#A\001\004y\023!B5o\003\036,\007\"\002\016\001\t\0031E\003\002\017H\021&CQ!E#A\002IAQ\001R#A\002=BQAS#A\002I\t\001\"\0338HK:$WM\035\005\0065\001!\t\001\024\013\0029\001")
public class Father04 {
private String name;
private int age;
private String gender;
public String name() {
return this.name;
}
public void name_$eq(String x$1) {
this.name = x$1;
}
public int age() {
return this.age;
}
public void age_$eq(int x$1) {
this.age = x$1;
}
public String gender() {
return this.gender;
}
public void gender_$eq(String x$1) {
this.gender = x$1;
}
public Father04(String inName, int inAge) {
this(inName);
age_$eq(inAge);
Predef$.MODULE$.println(");
}
public Father04(String inName, int inAge, String inGender) {
this(inName, inAge);
gender_$eq(inGender);
Predef$.MODULE$.println(");
}
public Father04() {
this("Lucy");
Predef$.MODULE$.println(");
}
public Father04(String inName) {
this.name = inName;
Predef$.MODULE$.println(");
Predef$.MODULE$.println(");
}
}
2.5 覆写字段
public class JavaFieldOverride {
public static void main(String[] args) {
/**
*总结:
* 1.对于同一个对象,用父类的引用去取值(字段),会取到父类字段的值
* 2.用子类的引用去取值(字段),则取到子类字段的值
**/
Sub s1 = new Sub();
Super s2 = new Sub();
System.out.println(s1.s); //输出sub
System.out.println(((Super)s1).s); //输出super --通过强转,可以访问到父类被隐藏的字段
System.out.println(s2.s); //输出super --通过父类引用,访问隐藏的字段
}
}
class Super {
String s = "super";
}
class Sub extends Super {
String s = "sub";
}
2.6 动态绑定机制
public class JavaDynamicBind {
public static void main(String[] args) {
/**
*java动态绑定机制:
* 将一个子类对象地址,交给一个父类的引用:
* 1.如果调用的是方法,则jvm机会将该方法和和对象的内存地址绑定
* 2.如果调用的是属性,则没有动态绑定机制,在哪里调用,就返回对应值
**/
A a = new B();
System.out.println(a.sum()); //输出20+10=30
System.out.println(a.sum1()); //输出10+10=20
}
}
class A {
public int i = 10;
public int sum() {
return getI() + 10;
}
public int sum1() {
return i + 10;
}
public int getI() {
return i;
}
}
class B extends A {
public int i = 20;
// public int sum() {
// return i + 20;
// }
public int getI() {
return i;
}
// public int sum1() {
// return i + 10;
// }
}
package scalaDemo.extendsDemo.demo03
object ScalaFieldOverride {
def main(args: Array[String]): Unit = {
val fa: Father05 = new Son05
val son: Son05 = new Son05
println(fa.name) //fa.name() --动态绑定机制,实际调用子类的name()
println(son.name) //son.name()
}
}
class Father05 {
val name = "Lucy" //public String name(){}
}
class Son05 extends Father05 {
override val name: String = "sunny" //public String name(){}
}
反编译代码:
package scalaDemo.extendsDemo.demo03;
import scala.reflect.ScalaSignature;
@ScalaSignature(bytes = "\006\001\t2A!\001\002\001\023\tAa)\031;iKJ\004TG\003\002\004\t\0051A-Z7paMR!!\002\004\002\027\025DH/\0328eg\022+Wn\034\006\002\017\005I1oY1mC\022+Wn\\\002\001'\t\001!\002\005\002\f\0355\tABC\001\016\003\025\0318-\0317b\023\tyAB\001\004B]f\024VM\032\005\006#\001!\tAE\001\007y%t\027\016\036 \025\003M\001\"\001\006\001\016\003\tAqA\006\001C\002\023\005q#\001\003oC6,W#\001\r\021\005eqR\"\001\016\013\005ma\022\001\0027b]\036T\021!H\001\005U\0064\030-\003\002 5\t11\013\036:j]\036Da!\t\001!\002\023A\022!\0028b[\026\004\003")
public class Father05 {
private final String name = "Lucy";
public String name() {
return this.name;
}
}
package scalaDemo.extendsDemo.demo03;
import scala.reflect.ScalaSignature;
@ScalaSignature(bytes = "\006\001\0052A!\001\002\001\023\t)1k\03481k)\0211\001B\001\007I\026lw\016M\032\013\005\0251\021aC3yi\026tGm\035#f[>T\021aB\001\ng\016\fG.\031#f[>\034\001a\005\002\001\025A\0211\002D\007\002\005%\021QB\001\002\t\r\006$\b.\032:1k!)q\002\001C\001!\0051A(\0338jiz\"\022!\005\t\003\027\001Aqa\005\001C\002\023\005C#\001\003oC6,W#A\013\021\005YabBA\f\033\033\005A\"\"A\r\002\013M\034\027\r\\1\n\005mA\022A\002)sK\022,g-\003\002\036=\t11\013\036:j]\036T!a\007\r\t\r\001\002\001\025!\003\026\003\025q\027-\\3!\001")
public class Son05 extends Father05 {
private final String name = "sunny";
public String name() {
return this.name;
}
}
2.7 覆写字段注意事项
package scalaDemo.extendsDemo.demo03
object ScalaFieldOverrideDetail {
def main(args: Array[String]): Unit = {
val son = new Son06
}
}
/**
* 1.抽象字段(属性):就是没有初始化的字段
* 2.当一个类中含有抽象属性时,则该类需要标记为abstract
* 3.对于抽象的属性,在底层不会生成对应的属性声明(成员变量),而是生成两个对应的抽象方法(name()、name_$eq())
**/
abstract class Father06 {
var name: String //抽象字段,可重写
var age: Int = 99 //var非抽象属性,不能重写
}
/**
* 说明:
* 1.如果在子类中重写了父类的抽象属性,本质上是实现了抽象方法
* 2.因此override也可以不写
**/
class Son06 extends Father06 {
override var name: String = "Lucy" //override可省略
//override var age: Int = 18 //错误写法,因为var只能重写另一个抽象的var属性,否则运行会报错
}
反编译代码:
package scalaDemo.extendsDemo.demo03;
import scala.reflect.ScalaSignature;
public abstract class Father06 {
private int age = 99;
public abstract String name();
public abstract void name_$eq(String paramString);
public int age() {
return this.age;
}
public void age_$eq(int x$1) {
this.age = x$1;
}
}
package scalaDemo.extendsDemo.demo03;
import scala.reflect.ScalaSignature;
public class Son06 extends Father06 {
private String name = "Lucy";
public String name() {
return this.name;
}
public void name_$eq(String x$1) {
this.name = x$1;
}
}
2.8 抽象类
package scalaDemo.extendsDemo.demo03
object AbstractClass {
def main(args: Array[String]): Unit = {
//临时创建一个匿名子类
val dog = new Animal02 {
override var name: String = "dog"
override var sex: String = "雌性"
override def describ(): String = {
s"name: $name\nsex: $sex"
}
override def action(): Unit = {
println("正在追赶小偷...")
}
}
val cat = new Animal02 {
override var name: String = "cat"
override var sex: String = "雄性"
override def describ(): String = {
s"name: $name\nsex: $sex"
}
override def action(): Unit = {
println("正在抓老鼠...")
}
}
println(dog.describ())
dog.action()
println(cat.describ())
cat.action()
}
}
abstract class Animal02 {
var name: String //抽象属性
var sex: String
val name2 = "Animal01" //普通属性
def describ(): String //抽象方法
def action() //抽象方法
/**
* @Author: qwerdf@QAQ
* @Description:
* 总结:
* 1.抽象类不能被实例化,可以通过创建匿名子类对象来实现
* 2.抽象类不一定有abstract方法,但是含有抽象方法或抽象属性的一定是抽象类
* 3.scala中抽象方法不能用abstract标记,定义方式:def temp()
* 4.如果一个类继承了抽象类,则必须实现抽象类的所以抽象方法和抽象属性,除非它自己也声明为abstract类
* 5.抽象方法和抽象属性不能使用private、final来修饰,因为这些关键字都是和重写/实现相违背的
* 6.抽象类可以有实现的方法
* 7.子类重写抽象方法不需要override,也可以加上
* @Date: 2021/3/14
* @Param null:
* @return: null
**/
}
2.9 匿名子类
3.内部类
3.1 基本使用
3.2 属性访问
4.伴生类与伴生对象
5.样例类
package scalaDemo
object CaseClassV1 {
def main(args: Array[String]): Unit = {
val arr = Array(
Teacher01A("张三", 33), Teacher01A("李四", 26),
Student01A("小明", 9), Student01A("小红", 19),
Stranger01A
)
for (person <- arr) {
println(matchCase(person))
}
}
def matchCase(person: AnyRef) = {
person match {
case Teacher01A(name, age) => s"name=$name|age=$age 允许教师进入..."
case Student01A(name, age) => {
if (age < 18)
s"name=$name|age=$age 允许未成年学生进入..."
else
s"name=$name|age=$age 允许成年学生进入..."
}
case Stranger01A => s"禁止陌生人进入!!!"
case _ => s"错误类型匹配!!!"
}
}
}
/**
* 1.case类是一种特殊的类,它们经过优化以被用于模式匹配,构造参数默认为val;
* 2.当定义一个类时,如果在class关键字前加上case关键字,则该类称为case类;
* 3.Scala为case类自动重载了许多实用的方法,包括toString、equals和hashcode方法;
* 4.Scala为每一个case类自动生成一个伴生对象,其包括模板代码1个apply方法,
* 因此,实例化case类的时候无需使用new关键字。和1个unapply方法,
* 该方法包括一个类型为伴生类的参数返回的结果是Option类型,对应的类型参数是N元组,
* N是伴生类中主构造器参数的个数。Unapply方法用于对对象进行解构操作,
* 在case类模式匹配中,该方法被自动调用,并将待匹配的对象作为参数传递给它。
**/
case class Teacher01A(name: String, age: Int)
case class Student01A(name: String, age: Int)
object Stranger01A
反编译代码:
package scalaDemo;
import scala.Function1;
import scala.Option;
import scala.Product;
import scala.Serializable;
import scala.Tuple2;
import scala.collection.Iterator;
import scala.reflect.ScalaSignature;
import scala.runtime.BoxesRunTime;
import scala.runtime.ScalaRunTime$;
import scala.runtime.Statics;
public class Student01A implements Product, Serializable {
private final String name;
private final int age;
public static Option<Tuple2<String, Object>> unapply(Student01A paramStudent01A) {
return Student01A$.MODULE$.unapply(paramStudent01A);
}
public static Student01A apply(String paramString, int paramInt) {
return Student01A$.MODULE$.apply(paramString, paramInt);
}
public static Function1<Tuple2<String, Object>, Student01A> tupled() {
return Student01A$.MODULE$.tupled();
}
public static Function1<String, Function1<Object, Student01A>> curried() {
return Student01A$.MODULE$.curried();
}
public String name() {
return this.name;
}
public int age() {
return this.age;
}
public Student01A copy(String name, int age) {
return new Student01A(name, age);
}
public String copy$default$1() {
return name();
}
public int copy$default$2() {
return age();
}
public String productPrefix() {
return "Student01A";
}
public int productArity() {
return 2;
}
public Object productElement(int x$1) {
int i = x$1;
switch (i) {
default:
throw new IndexOutOfBoundsException(BoxesRunTime.boxToInteger(x$1).toString());
case 1:
case 0:
break;
}
return name();
}
public Iterator<Object> productIterator() {
return ScalaRunTime$.MODULE$.typedProductIterator(this);
}
public boolean canEqual(Object x$1) {
return x$1 instanceof Student01A;
}
public int hashCode() {
int i = -889275714;
i = Statics.mix(i, Statics.anyHash(name()));
i = Statics.mix(i, age());
return Statics.finalizeHash(i, 2);
}
public String toString() {
return ScalaRunTime$.MODULE$._toString(this);
}
public boolean equals(Object x$1) {
// Byte code:
// 0: aload_0
// 1: aload_1
// 2: if_acmpeq -> 92
// 5: aload_1
// 6: astore_2
// 7: aload_2
// 8: instanceof scalaDemo/Student01A
// 11: ifeq -> 19
// 14: iconst_1
// 15: istore_3
// 16: goto -> 21
// 19: iconst_0
// 20: istore_3
// 21: iload_3
// 22: ifeq -> 96
// 25: aload_1
// 26: checkcast scalaDemo/Student01A
// 29: astore #4
// 31: aload_0
// 32: invokevirtual name : ()Ljava/lang/String;
// 35: aload #4
// 37: invokevirtual name : ()Ljava/lang/String;
// 40: astore #5
// 42: dup
// 43: ifnonnull -> 55
// 46: pop
// 47: aload #5
// 49: ifnull -> 63
// 52: goto -> 88
// 55: aload #5
// 57: invokevirtual equals : (Ljava/lang/Object;)Z
// 60: ifeq -> 88
// 63: aload_0
// 64: invokevirtual age : ()I
// 67: aload #4
// 69: invokevirtual age : ()I
// 72: if_icmpne -> 88
// 75: aload #4
// 77: aload_0
// 78: invokevirtual canEqual : (Ljava/lang/Object;)Z
// 81: ifeq -> 88
// 84: iconst_1
// 85: goto -> 89
// 88: iconst_0
// 89: ifeq -> 96
// 92: iconst_1
// 93: goto -> 97
// 96: iconst_0
// 97: ireturn
// Line number table:
// Java source line number -> byte code offset
// #44 -> 0
// Local variable table:
// start length slot name descriptor
// 0 98 0 this LscalaDemo/Student01A;
// 0 98 1 x$1 Ljava/lang/Object;
}
public Student01A(String name, int age) {
Product.class.$init$(this);
}
}
package scalaDemo;
import scala.Option;
import scala.Serializable;
import scala.Some;
import scala.Tuple2;
import scala.runtime.AbstractFunction2;
import scala.runtime.BoxesRunTime;
public final class Student01A$ extends AbstractFunction2<String, Object, Student01A> implements Serializable {
public static final Student01A$ MODULE$;
public final String toString() {
return "Student01A";
}
public Student01A apply(String name, int age) {
return new Student01A(name, age);
}
public Option<Tuple2<String, Object>> unapply(Student01A x$0) {
return (x$0 == null) ? (Option<Tuple2<String, Object>>)scala.None$.MODULE$ : (Option<Tuple2<String, Object>>)new Some(new Tuple2(x$0.name(), BoxesRunTime.boxToInteger(x$0.age())));
}
private Object readResolve() {
return MODULE$;
}
private Student01A$() {
MODULE$ = this;
}
}
三、特质trait
1.动态混入
package scalaDemo.traitDemo
object MixInTraitV1 {
def main(args: Array[String]): Unit = {
/**
* 说明:
* 1.定义关键字trait。特质类似于java中的接口,java中实现接口关键字"implements",scala中使用"with"
* 如class A extends classB with traitC with traitD …
**/
val sql03 = new MySql03 with Oper03
val sql04 = new MySql04 with Oper03
//如果抽象类中有抽象方法,需要实现
val sql05 = new MySql05 with Oper03 {
override def insert(num: Double): Unit = {
println(s"插入数据: $num")
}
}
sql03.delete(3.14)
sql04.delete(6.28)
sql05.insert(9.42)
}
}
trait Oper03 {
def delete(num: Double) = {
println(s"删除数据: $num")
}
}
class MySql03 {
}
abstract class MySql04 {
}
abstract class MySql05 {
def insert(num: Double)
}
2. 叠加特质
package scalaDemo.traitDemo
object MixInTraitV2 {
def main(args: Array[String]): Unit = {
/**
* 说明:
* 动态混入对象时,初始化顺序
* 1.Oper06A...
* 2.Oper06B...
* 3.Oper06C1...
* 4.Oper06C2...
*
* 调用delete方法执行顺序
* 1.Oper06C2-删除数据:3.14
* 2.Oper06C1-删除数据:3.14
* 3.Oper06B-删除数据:3.14
**/
val sql06 = new MySql06 with Oper06C1 with Oper06C2
println("======================================")
sql06.delete(3.14)
}
}
class MySql06 {
}
trait Oper06A {
println("Oper06A...")
def delete(num: Double)
}
trait Oper06B extends Oper06A { //特质,继承Oper06A
println("Oper06B...")
//实现或重写Oper06A中的抽象方法,override可省略
override def delete(num: Double): Unit = {
println(s"Oper06B-删除数据:$num")
}
}
trait Oper06C1 extends Oper06B {
println("Oper06C1...")
//由于Oper06B中已经实现delete方法,这里只能是重写,override不能省略
override def delete(num: Double): Unit = {
println(s"Oper06C1-删除数据:$num")
//动态混入时,这里不一定调用的是父类Oper06B中的方法
//得看混入顺序--new MySql06 with Oper06C1 with Oper06C2
super.delete(num)
}
}
trait Oper06C2 extends Oper06B {
println("Oper06C2...")
override def delete(num: Double): Unit = {
println(s"Oper06C2-删除数据:$num")
//动态混入时,这里不一定调用的是父类Oper06B中的方法
//得看混入顺序--new MySql06 with Oper06C1 with Oper06C2
super.delete(num)
//可以指定具体类型,从而访问到Oper06B中的delete方法
//super[Oper06B].delete(num)
//super[Oper06A].delete(num) 执行报错,因为Oper06A不是当前特质的直接父特质(超类)
}
}
3.富接口
4.特质中的字段
package scalaDemo.traitDemo
object MixInTraitV3 {
def main(args: Array[String]): Unit = {
val sql07 = new MySql07 with Oper07 {
override var oper_date: String = _
}
}
}
class MySql07 {
}
trait Oper07 {
val num: Int = 66
var oper_type: String = "insert"
var oper_date: String //抽象字段
def insert() = {
}
}
反编译代码:
package scalaDemo.traitDemo;
import scala.runtime.TraitSetter;
public final class MixInTraitV3$ {
public static final MixInTraitV3$ MODULE$;
public void main(String[] args) {
MySql07 sql07 = new MixInTraitV3$$anon$1();
}
public final class MixInTraitV3$$anon$1 extends MySql07 implements Oper07 {
private String oper_date;
private final int num;
private String oper_type;
public int num() {
return this.num;
}
public String oper_type() {
return this.oper_type;
}
@TraitSetter
public void oper_type_$eq(String x$1) {
this.oper_type = x$1;
}
public void scalaDemo$traitDemo$Oper07$_setter_$num_$eq(int x$1) {
this.num = x$1;
}
public void insert() {
Oper07$class.insert(this);
}
public MixInTraitV3$$anon$1() {
Oper07$class.$init$(this);
}
public String oper_date() {
return this.oper_date;
}
public void oper_date_$eq(String x$1) {
this.oper_date = x$1;
}
}
private MixInTraitV3$() {
MODULE$ = this;
}
}
5.特质构造顺序
package scalaDemo.traitDemo
object MixInTraitV4 {
def main(args: Array[String]): Unit = {
/**
* 说明:
* 声明类时混入特质,即静态混入,初始化顺序
* class MySql08B extends MySql08A with Oper08C1 with Oper08C2
* 1.MySql08A...
* 2.Oper08A...
* 3.Oper08B...
* 4.Oper08C1...
* 5.Oper08C2...
* 6.MySql08B...
*
* 动态混入特质,初始化顺序
* new MySql08C with Oper08C1 with Oper08C2
* 1.MySql08A...
* 2.MySql08C...
* 3.Oper08A...
* 4.Oper08B...
* 5.Oper08C1...
* 6.Oper08C2...
*
* 调用delete方法执行顺序
* 1.Oper08C2-删除数据:3.14
* 2.Oper08C1-删除数据:3.14
* 3.Oper08B-删除数据:3.14
*
* 1.Oper08C2-删除数据:6.28
* 2.Oper08C1-删除数据:6.28
* 3.Oper08B-删除数据:6.28
**/
val sql08b = new MySql08B
println("===================================")
//动态混入
val sql08c = new MySql08C with Oper08C1 with Oper08C2
println("===================================")
//调用方法执行顺序
sql08b.delete(3.14)
println("===================================")
sql08c.delete(6.28)
}
}
class MySql08A {
println("MySql08A...")
}
class MySql08B extends MySql08A with Oper08C1 with Oper08C2 {
println("MySql08B...")
}
class MySql08C extends MySql08A {
println("MySql08C...")
}
trait Oper08A {
println("Oper08A...")
def delete(num: Double)
}
trait Oper08B extends Oper08A {
println("Oper08B...")
override def delete(num: Double): Unit = {
println(s"Oper08B-删除数据:$num")
}
}
trait Oper08C1 extends Oper08B {
println("Oper08C1...")
override def delete(num: Double): Unit = {
println(s"Oper08C1-删除数据:$num")
super.delete(num)
}
}
trait Oper08C2 extends Oper08B {
println("Oper08C2...")
override def delete(num: Double): Unit = {
println(s"Oper08C2-删除数据:$num")
super.delete(num)
}
}
6.扩展类的特质
7.自身类型
四、隐式转换
1.隐式函数
package scalaDemo.implicitDemo.implicitFunction
object ImplicitFuncV1 {
def main(args: Array[String]): Unit = {
//底层编译成double2Int$1(double d)
implicit def double2Int(d: Double) = {
d.toInt
}
val num: Int = 3.14 //double2Int$1(3.14)
}
}
反编译代码:
package scalaDemo.implicitDemo.implicitFunction;
public final class ImplicitFuncV1$ {
public static final ImplicitFuncV1$ MODULE$;
private final int double2Int$1(double d) {
return (int)d;
}
public void main(String[] args) {
int num = double2Int$1(3.14D);
}
private ImplicitFuncV1$() {
MODULE$ = this;
}
}
package scalaDemo.implicitDemo.implicitFunction
object ImplicitFuncV2 {
implicit def addDelete(mysql: MySql01) = {
new Oper01
}
def main(args: Array[String]): Unit = {
// implicit def addDelete(mysql: MySql01) = {
// new Oper01
// }
val sql = new MySql01
sql.insert(9)
/**
* 说明:
* 1.当隐式函数定义在main方法内时: addDelete$1(sql).delete(10)
* 2.当隐式函数定义在main方法外时: addDelete(sql).delete(10)
**/
sql.delete(10)
}
}
class MySql01 {
def insert(num: Int) = {
println(s"插入数据:$num")
}
}
class Oper01 {
def delete(num: Int) = {
println(s"删除数据: $num")
}
}
反编译代码:
package scalaDemo.implicitDemo.implicitFunction;
public final class ImplicitFuncV2$ {
public static final ImplicitFuncV2$ MODULE$;
public Oper01 addDelete(MySql01 mysql) {
return new Oper01();
}
public void main(String[] args) {
MySql01 sql = new MySql01();
sql.insert(9);
addDelete(sql).delete(10);
}
private ImplicitFuncV2$() {
MODULE$ = this;
}
}
2.隐式值
package scalaDemo.implicitDemo.implicitValue
object ImplicitValueV1 {
def main(args: Array[String]): Unit = {
implicit val name: String = "Lucy" //隐式值
//底层函数名:showInfo$1
def showInfo(implicit inName: String) = {
println(s"name is $inName")
//showInfo$2
def showInfo() = {
println("main -> showInfo -> showInfo")
}
}
showInfo
}
//showInfo
def showInfo() = {
println("object -> showInfo")
}
}
反编译代码:
package scalaDemo.implicitDemo.implicitValue;
import scala.StringContext;
import scala.collection.Seq;
public final class ImplicitValueV1$ {
public static final ImplicitValueV1$ MODULE$;
public void main(String[] args) {
String name = "Lucy";
showInfo$1(name);
}
private final void showInfo$1(String inName) {
(new String[2])[0] = "name is ";
(new String[2])[1] = "";
scala.Predef$.MODULE$.println((new StringContext((Seq)scala.Predef$.MODULE$.wrapRefArray((Object[])new String[2]))).s((Seq)scala.Predef$.MODULE$.genericWrapArray(new Object[] { inName })));
}
private final void showInfo$2() {
scala.Predef$.MODULE$.println("main -> showInfo -> showInfo");
}
public void showInfo() {
scala.Predef$.MODULE$.println("object -> showInfo");
}
private ImplicitValueV1$() {
MODULE$ = this;
}
}
package scalaDemo.implicitDemo.implicitValue
object ImplicitValueV2 {
def main(args: Array[String]): Unit = {
implicit val name: String = "Lucy"
// implicit val name2: String = "Lucy2" 不能有两个相同类型的隐式值,否则编译器会无法识别
/***
* 说明
* 1.隐式值优先级:传值 > 隐式值 > 默认值
* 2.隐式值匹配时不能有二义性
* 3.如果调用方法时,传值、隐式值、默认值都没有,程序会报错
**/
showInfo1 //输出Lucy
showInfo1("@sunny") //输出@sunny
showInfo2 //输出18
//showInfo3//不传值会报错
}
def showInfo1(implicit inName: String = "sunny")= {
println(s"name is $inName")
}
def showInfo2(implicit inAge: Int = 18) = {
println(s"age is $inAge")
}
def showInfo3(implicit inAge: Int) = {
println(s"age is $inAge")
}
}
反编译代码:
package scalaDemo.implicitDemo.implicitValue;
import scala.StringContext;
import scala.collection.Seq;
import scala.runtime.BoxesRunTime;
public final class ImplicitValueV2$ {
public static final ImplicitValueV2$ MODULE$;
public void main(String[] args) {
String name = "Lucy";
showInfo1(name);
showInfo1("@sunny");
showInfo2(showInfo2$default$1());
}
public String showInfo1$default$1() {
return "sunny";
}
public void showInfo1(String inName) {
(new String[2])[0] = "name is ";
(new String[2])[1] = "";
scala.Predef$.MODULE$.println((new StringContext((Seq)scala.Predef$.MODULE$.wrapRefArray((Object[])new String[2]))).s((Seq)scala.Predef$.MODULE$.genericWrapArray(new Object[] { inName })));
}
public int showInfo2$default$1() {
return 18;
}
public void showInfo2(int inAge) {
(new String[2])[0] = "age is ";
(new String[2])[1] = "";
scala.Predef$.MODULE$.println((new StringContext((Seq)scala.Predef$.MODULE$.wrapRefArray((Object[])new String[2]))).s((Seq)scala.Predef$.MODULE$.genericWrapArray(new Object[] { BoxesRunTime.boxToInteger(inAge) })));
}
public void showInfo3(int inAge) {
(new String[2])[0] = "age is ";
(new String[2])[1] = "";
scala.Predef$.MODULE$.println((new StringContext((Seq)scala.Predef$.MODULE$.wrapRefArray((Object[])new String[2]))).s((Seq)scala.Predef$.MODULE$.genericWrapArray(new Object[] { BoxesRunTime.boxToInteger(inAge) })));
}
private ImplicitValueV2$() {
MODULE$ = this;
}
}
3.隐式类
package scalaDemo.implicitDemo.implicitClass
object ImplicitClassV1 {
def main(args: Array[String]): Unit = {
/***
*说明:
* implicit关键字声明一个class后,对应底层编译生成Oper02$1()方法,并返回隐式类ImplicitClassV1$Oper02$2
* private final ImplicitClassV1$Oper02$2 Oper02$1(MySql02 mysql) {
* return new ImplicitClassV1$Oper02$2(mysql);
* }
*
*总结:
* 1.隐式类的构造参数有且只能有一个
* 2.隐式类必须定义在类、伴生对象、包对象里面,不能是顶级的objects
* 3.隐式类不能是case class
* 4.作用域内不能有同名标识符,否则编译器无法识别
**/
implicit class Oper02(val mysql: MySql02) {
def delete(sql: MySql02) = {
println(s"delete num: ${sql.num}")
}
}
val sql02 = new MySql02
sql02.insert()
sql02.delete(sql02) //Oper02$1(sql02).delete(sql02)
}
// implicit class Oper02(val mysql: MySql02) {
// def delete(sql: MySql02) = {
// println(s"delete num: ${sql.num}")
// }
// }
}
class MySql02 {
val num = 3.14
def insert(num2: Double = 6.28) = {
println(s"insert num: $num2")
}
}
反编译代码:
package scalaDemo.implicitDemo.implicitClass;
public final class ImplicitClassV1$ {
public static final ImplicitClassV1$ MODULE$;
private final ImplicitClassV1$Oper02$2 Oper02$1(MySql02 mysql) {
return new ImplicitClassV1$Oper02$2(mysql);
}
public void main(String[] args) {
MySql02 sql02 = new MySql02();
sql02.insert(sql02.insert$default$1());
Oper02$1(sql02).delete(sql02);
}
private ImplicitClassV1$() {
MODULE$ = this;
}
}
上述生成的隐式类ImplicitClassV1$Oper02$2结构可参考下图:
五、集合
1.集合基本介绍
2.数组
2.1 定长数组
1)定义方式
//通过new的方式
val arr1 = new Array [Int] (3) //指定长度为3。Int类型初始化为0
val arr2 = new Array [String] (3) //String类型初始化为null
//通过apply方法
//apply方法内部通过new Array [T] ()
val arr3 = Array(1,"scala",3,14)
val arr4 = Array.apply(1,"scala",3,14*2)
2)定长数组赋值、修改
//通过下标赋值、修改值
arr2(0) = "章子怡"
arr2(1) = "王菲"
arr2(1) = "鞠婧祎"
//返回:ArrayBuffer(章子怡, 鞠婧祎, null)
3)数组转List
val list1: immutable.Seq[String] = arr2.toList
val list2: List[String] = arr2.toList
4)遍历数组元素
//通过下标取值
for (i <- 0 until arr3.length) {
println(s"$i==${arr4(i)}")
}
//直接循环出数组元素
for (i <- arr4) {
println(i)
}
//foreach方式
arr03.foreach {
x => println(x)
}
package scalaDemo.collectionDemo.array
object ArrayV1 {
def main(args: Array[String]): Unit = {
//通过new的方式
val arr01 = new Array[Any](3)
arr01(0) = "Lucy"
arr01(1) = "sunny"
//通过apply方法
val arr02 = Array("Lucy","sunny",3.14)
val arr03 = Array.apply("@Lucy","@sunny",3.14*2)
//直接循环出数组元素
for (elem <- arr01) {
println(elem)
}
println("===========================")
//通过下标取值
for (i <- 0 until arr02.length) {
println(arr02(i))
}
println("===========================")
//foreach方式
arr03.foreach {
x => println(x)
}
}
}
2.2 变长数组
1)定义方式
//需要引入mutable下面的包
import scala.collection.mutable.{ArrayBuffer, ListBuffer}
//通过new的方式
val buffer1 = new ArrayBuffer[String] ()
buffer1 += "王祖贤"
buffer1 += "林青霞"
//通过apply方法
val buffer2 = ArrayBuffer("赵丽颖","鞠婧祎")
val buffer3 = ArrayBuffer.apply("李一桐","周迅")
2)添加元素
//添加多种类型元素
arr03.append("@sunny",("@Lucy",18))
arr03 += (3.14*2,3.14*3,("@Lucy",19))
3)删除元素
buffer3.remove(1) //删除下标为1的元素
4)遍历元素
//遍历元素
//方式1
for (elem <- arr01) {
println(elem)
}
println("==========================")
//方式2
for (i <- 0 until arr02.length) {
println(arr02(i))
}
println("==========================")
//方式3
arr03.foreach {
x => println(x)
}
5)排序
val buffer4 = ArrayBuffer(1,3,5,7,6,4,2,0)
val buffer4_1 = buffer4.sortWith(_<_)
val buffer4_2 = buffer4.sortWith((x,y) => x < y)
package scalaDemo.collectionDemo.array
import scala.collection.mutable.ArrayBuffer
object ArrayV2 {
def main(args: Array[String]): Unit = {
//通过new的方式
val arr01 = new ArrayBuffer[Any]()
//添加元素
arr01.append("Lucy")
arr01 += "sunny"
通过apply方法
val arr02 = ArrayBuffer("Lucy","sunny",3.14)
val arr03 = ArrayBuffer.apply("@Lucy","@sunny",3.14*2)
//遍历元素
//方式1
for (elem <- arr01) {
println(elem)
}
println("==========================")
//方式2
for (i <- 0 until arr02.length) {
println(arr02(i))
}
println("==========================")
//方式3
arr03.foreach {
x => println(x)
}
}
}
2.3 定长数组与变长数组的转换
package scalaDemo.collectionDemo.array
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
object ArrayV3 {
def main(args: Array[String]): Unit = {
val arr01 = Array("Lucy","sunny")
val arr02 = new ArrayBuffer[Any]()
arr02.append("@Lucy","@sunny")
//定长转变长数组
//底层new mutable.ArrayBuffer[A1](size)
val arr03: mutable.Buffer[Any] = arr01.toBuffer
//添加多种类型元素
arr03.append("@sunny",("@Lucy",18))
arr03 += (3.14*2,3.14*3,("@Lucy",19))
//变长转定长数组
//底层new Array[B](size)
val arr04: Array[Any] = arr02.toArray
arr03.foreach(println(_))
println("=========================")
arr04.foreach(println(_))
}
}
2.4 多维数组
2.5 Java的List转Scala数组
3.元组
package scalaDemo.collectionDemo.tuple
object TupleV1 {
def main(args: Array[String]): Unit = {
//创建
//tuple01是一个Tuple,类型是Tuple4
val tuple01: (String, String, Int, Int) = ("Lucy","sunny",18,19)
}
}
反编译代码:
package scalaDemo.collectionDemo.tuple;
import scala.Tuple4;
import scala.runtime.BoxesRunTime;
public final class TupleV1$ {
public static final TupleV1$ MODULE$;
public void main(String[] args) {
Tuple4 tuple01 = new Tuple4("Lucy", "sunny", BoxesRunTime.boxToInteger(18), BoxesRunTime.boxToInteger(19));
}
private TupleV1$() {
MODULE$ = this;
}
}
package scalaDemo.collectionDemo.tuple
object TupleV1 {
def main(args: Array[String]): Unit = {
//创建
//tuple01是一个Tuple,类型是Tuple4
val tuple01: (String, String, Int, Int) = ("Lucy","sunny",18,19)
//访问元素
//根据顺序号--第一个元素
println(tuple01.productElement(0))
//根据索引--第一个元素
/**
* 底层实现:scala.Product4中的方法,含有Product1~Product22
* 具体根据元组的类型去调用哪个Product中的方法,这里为scala.Product4
* override def productElement(n: Int) = n match {
* case 0 => _1
* case 1 => _2
* case 2 => _3
* case 3 => _4
* case _ => throw new IndexOutOfBoundsException(n.toString())
* }
**/
tuple01.productElement(0)
}
}
//遍历元组
val tuple02 = ("@Lucy","@sunny",3.14)
val iterator: Iterator[Any] = tuple02.productIterator
for (item <- iterator) {
println(item)
}
4.列表List
4.1 不可变List
1)定义方式
//创建
val lis01 = List("Lucy","sunny",18,19)
val lis02 = Nil //表示一个空集合List()
2)元素访问
//访问List元素
val lis03 = List("@Lucy","@sunny",18,19,20)
println(lis03(0)) //索引从0开始,取出第一个元素
3)元素追加
//追加元素--生成新List,原集合不变
//方式1 :+
val lis04 = List("A","B","C")
val lis05 = lis04 :+ "Lucy" //在列表最后追加元素
//方式2 +:
val lis06 = "sunny" +: lis04 //在列表前边追加元素
println(lis04) //List(A, B, C)
println(lis05) //List(A, B, C, Lucy)
println(lis06) //List(sunny, A, B, C)
//方式3 ::
val lis07 = List("A","B","C")
//向一个空列表添加元素
val lis08 = 1::2::3::lis07::Nil
println(lis08) //List(1, 2, 3, List(A, B, C))
//方式4 ::: 该符号左右必须是集合才能使用
//将集合中的每一个元素添加到空集合
val lis09 = 1::2::3::lis07:::Nil
println(lis09) //List(1, 2, 3, A, B, C)
4.2 可变List
package scalaDemo.collectionDemo.list
import scala.collection.mutable.ListBuffer
object ListV2 {
def main(args: Array[String]): Unit = {
//创建
val lis01 = new ListBuffer[Any] //创建一个空list
val lis02 = ListBuffer[Any]("Lucy","sunny",3.14)
val lis03 = ListBuffer("Lucy","sunny",3.14)
println(lis01) //ListBuffer()
println(lis02) //ListBuffer(Lucy, sunny, 3.14)
println(lis03) //ListBuffer(Lucy, sunny, 3.14)
//添加元素 +=、append、++=不会生成一个新得集合
val lis04 = new ListBuffer[Any]() //可省略()
lis04 += ("@Lucy","@sunny")
lis04.append("A","B",18)
println(lis04) //ListBuffer(@Lucy, @sunny, A, B, 18)
val lis05 = ListBuffer(3.14,6.28)
lis04 ++= lis05
println(lis04) //ListBuffer(@Lucy, @sunny, A, B, 18, 3.14, 6.28)
// ++、:+、+: 会生成一个新的集合
val lis06 = ListBuffer("Lucy","@Lucy")
val lis07 = ListBuffer("加菲猫","中华田园犬")
val lis08 = lis06 ++ lis07
val lis09 = lis08 :+ "1998"
val lis10 = "1998" +: lis08
println(lis06) //ListBuffer(Lucy, @Lucy)
println(lis07) //ListBuffer(加菲猫, 中华田园犬)
println(lis08) //ListBuffer(Lucy, @Lucy, 加菲猫, 中华田园犬)
println(lis09) //ListBuffer(Lucy, @Lucy, 加菲猫, 中华田园犬, 1998)
println(lis10) //ListBuffer(1998, Lucy, @Lucy, 加菲猫, 中华田园犬)
//删除元素
val elem = lis10.remove(0) //可以不用变量接收
println(s"删除的元素:$elem") //删除的元素:1998
println(lis10) //ListBuffer(Lucy, @Lucy, 加菲猫, 中华田园犬)
}
}
5.队列Queue
1)创建队列
2)添加、删除元素
3)返回队列元素
package scalaDemo.collectionDemo.queue
import scala.collection.mutable.Queue
object QueueV1 {
def main(args: Array[String]): Unit = {
//创建
val que01 = new Queue[Any]
//添加元素
que01 += "Lucy"
que01 ++= List(1,2,3)
println(que01) //Queue(Lucy, 1, 2, 3)
que01 += List('A','B','C')
println(que01) //Queue(Lucy, 1, 2, 3, List(A, B, C))
//从队列的头部取出元素,队列que01本身也会变
val elem = que01.dequeue()
println(s"elem==$elem") //elem==Lucy
println(que01) //Queue(1, 2, 3, List(A, B, C))
//默认从尾部入队列,队列que01本身也会变
que01.enqueue(3.14,6.28,9.32)
println(que01) //Queue(1, 2, 3, List(A, B, C), 3.14, 6.28, 9.32)
//返回队列元素,队列que02本身不变
val que02 = new Queue[Any]
que02 ++= List('A','B','C','D')
//获取队列的第一个元素
println(s"head:${que02.head}") //head:A
//获取队列的最后一个元素
println(s"last:${que02.last}") //last:D
//获取队尾元素,即返回除了第一个以外剩余的元素
println(s"tail:${que02.tail}") //tail:Queue(B, C, D)
println(s"tail:${que02.tail.tail}") //tail:Queue(C, D)
}
}
6.映射Map
6.1 不可变Map
/**
* @inline def -> [B](y: B): Tuple2[A, B] = Tuple2(self, y)
* def →[B](y: B): Tuple2[A, B] = ->(y)
**/
//创建不可变Map--输出顺序和声明顺序一致
val map01 = Map("鞠婧祎" -> 25, "刘亦菲" -> 31)
val map02 = Map(("Lucy", 25), ("sunny", 31))
6.2 可变Map
package scalaDemo.collectionDemo.map
import scala.collection.mutable.Map
import scala.collection.mutable.HashMap
object MapV2 {
def main(args: Array[String]): Unit = {
//创建可变Map
val map01 = Map("杨幂" -> "三生三世十里桃花", "胡歌" -> "琅琊榜")
val map02 = Map(("Lucy", 25), ("sunny", 31))
//空集合--Map()
val map03 = new HashMap[String, Int]
//取值
//方式1:map(key)
println(map02("Lucy")) //key不存在会抛异常
//方式2:contains(key)先判断key是否存在
if (map02.contains("@sunny")) {
map02("@sunny")
}
//方式3:get(key)
val some01 = map02.get("Lucy")
val some02 = map02.get("@Lucy")
println(some01) //Some(25)
println(some02) //None
println(some01.get) //25
//println(some02.get) //None类型不能再get
//方式4:getOrElse(key,默认值)
val value01 = map02.getOrElse("Lucy~~", "-1")
println(value01) //-1
//修改和添加
val map04 = Map("杨幂" -> "三生三世十里桃花", "胡歌" -> "琅琊榜")
map04("胡歌") = "仙剑奇侠传" //key存在,更新value值
map04("鞠婧祎") = "叹云夕" //key不存在,相当于添加一个key-value
map04.update("杨幂", "古剑奇谭") //update更新value值
println(map04) //Map(鞠婧祎 -> 叹云夕, 胡歌 -> 仙剑奇侠传, 杨幂 -> 古剑奇谭)
// += 也能添加元素,如果key存在,则更新
map04 += "赵露思" -> "女"
map04 += ("杨紫" -> "女", "任嘉伦" -> "男")
map04 += (("Lucy", "女"), ("@Lucy", "女"))
println(map04) //Map(任嘉伦 -> 男, 鞠婧祎 -> 叹云夕, 胡歌 -> 仙剑奇侠传, 赵露思 -> 女, 杨紫 -> 女, 杨幂 -> 古剑奇谭, @Lucy -> 女, Lucy -> 女)
//删除--如果key不存在,也不会报错
map04 -= ("Lucy", "@Lucy")
println(map04) //Map(任嘉伦 -> 男, 鞠婧祎 -> 叹云夕, 胡歌 -> 仙剑奇侠传, 赵露思 -> 女, 杨紫 -> 女, 杨幂 -> 古剑奇谭)
//遍历
for ((k,v) <- map04) println(s"key==$k value==$v")
for (k <- map04.keys) println(s"key==$k")
for (v <- map04.values) println(s"value==$v")
for (tuple <- map04) println(s"key==${tuple._1} value==${tuple._2}")
}
}
7.Set
7.1 不可变Set
7.2 可变Set
package scalaDemo.collectionDemo.set
import scala.collection.mutable
import scala.collection.mutable.HashSet
object SetV1 {
def main(args: Array[String]): Unit = {
//创建
val set01 = mutable.Set.empty[Any]
val set02 = mutable.Set("Lucy",1,2,3)
val set03 = new HashSet[String] ()
val set04 = mutable.HashSet.empty[Any]
//添加元素
set01 += ("@Lucy","sunny",2008,2018)
set04.add("@Lucy")
println(set01) //Set(@Lucy, sunny,2008,2018)
//删除元素
set01 -= "sunny"
set01.remove(2008)
println(set01) //Set(@Lucy,2018)
//遍历
for (elem <- set01) println(elem)
set01.foreach {elem => println(elem)}
}
}
六、模式匹配
def matchCase(element: Any) = {
element match {
case a: Char => s"char类型$a"
case a: Int => s"int类型$a"
case a: Long => s"Long类型$a"
case a: Float => s"float类型$a"
case a: Double => s"double类型$a"
case a: Boolean => s"布尔类型$a"
case b: String => s"string类型$b"
case _ => s"未匹配到..."
}
}
七、函数
1.偏函数
package scalaDemo.partialFunDemo
object PartialFunctionV1 {
def main(args: Array[String]): Unit = {
val list = List(1, 2, 3,3.14, "Lucy")
val res01 = list.filter(_.isInstanceOf[Int]).map(func01(_))
val res02 = list.map(func02(_)).filter(_.isInstanceOf[Int])
println(res01)
println(res02)
//偏函数 可以处理多种类型
val func04 = new PartialFunction[Any, Int] {
override def isDefinedAt(x: Any): Boolean = x.isInstanceOf[Int] || x.isInstanceOf[Double]
override def apply(v1: Any): Int = if(v1.isInstanceOf[Int]) v1.asInstanceOf[Int]*2 else v1.asInstanceOf[Double].toInt +10
}
//偏函数简化形式
def func05: PartialFunction[Any, Int] = {
case x: Int => x * 2 //这里case语句可以自动转化成偏函数
case x: Double => x.toInt + 10
}
//如果使用偏函数,则不能使用map算子,应该使用collect(相当于map+filter组合使用)
val res04 = list.collect(func04)
val res05 = list.collect(func05)
println(res04)
println(res05)
}
def func01(x: Any): Int = {
x.asInstanceOf[Int] * 2
}
//模式匹配
def func02(x: Any) = {
x match {
case num: Int => num * 2
case _ =>
}
}
//偏函数
def func03 = {
val value = new PartialFunction[Any, Int] {
override def isDefinedAt(x: Any): Boolean = x.isInstanceOf[Int]
override def apply(v1: Any): Int = v1.asInstanceOf[Int] * 2
}
value
}
}
2.匿名函数
3.高阶函数
package scalaDemo.higherFunDemo
object HigherFunctionV1 {
def main(args: Array[String]): Unit = {
val res01 = hFuncA(funcA,3.14)
val res02 = hFuncA(funcB,6.28)
val res03 = hFuncA(funcC,9.42)
val res04 = hFuncB(funcC,funcD,9.42)
println(res01)
println(res02)
println(res03)
println(res04)
}
val funcA: Double => Int = num => num.toInt*2
def funcB = (num: Double) => num.toInt*2
def funcC(num: Double): Int = {
num.toInt*2
}
def funcD(num: Double) = {
num*num
}
def hFuncA(f: Double => Int, num: Double): Int = {
f(num)
}
def hFuncB(f1: Double => Int, f2: Double => Double, num: Double): Int = {
f1(f2(num))
}
}
package scalaDemo.higherFunDemo
object HigherFunctionV2 {
def main(args: Array[String]): Unit = {
val res01 = hFuncA(3)(3.14)
println(res01)
val func01 = hFuncA(4) // func01为3*y
val res02 = func01(3.14)
println(func01) //<function1>
println(res02)
}
//高阶函数也可以返回一个函数
def hFuncA(x: Int) = {
y: Double => x * y //匿名函数
}
}
package scalaDemo.higherFunDemo
object HigherFunctionV3 {
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4,5)
val res01 = list.map((x: Int) => x + 10) //map是一个高阶函数,可以直接传入匿名函数
val res02 = list.map((x) => x + 10) //由于list全是Int类型,在这里可推导出具体类型,所有可省略具体类型
val res03 = list.map(x => x + 10) //参数只有一个,可省略()
val res04 = list.map(_ + 10) //由于参数x在 => 右边只出现1次,可用_代替
println(res04)
val lis01 = list.reduce((x: Int,y: Int) => x + y)
val lis02 = list.reduce((x,y) => x + y)
val lis03 = list.reduce(_+_) //x和y在 => 右边只出现1次,可用_代替
println(lis03)
}
}
4.闭包
package scalaDemo.higherFunDemo
object HigherFunctionV4 {
def main(args: Array[String]): Unit = {
val res01 = hFuncA(funcA,"Lucy.jpg",".jpg")
val res02 = hFuncA(funcA,"sunny",".jpg")
println(res01)
println(res02)
println(hFuncB(".jpg")("@sunny"))
//闭包可以保留上次引用的某个值,传入一次可以反复使用
val endFunc = hFuncB(".jpg")
val list = List("Lucy.jpg","sunny","@sunny")
val res04 = list.map(endFunc) //.jpg传入一次,map遍历时多次使用
println(res04)
}
def funcA(file: String, end: String): String = {
if(file.endsWith(end)) {
file
} else
file + end
}
def hFuncA(f: (String, String) => String, file: String, end: String): String = {
funcA(file,end)
}
//这里匿名函数和end参数形成一个闭包
def hFuncB(end: String) = {
file: String => {
if(file.endsWith(end))
file
else
file + end
}
}
}
5.柯里化
package scalaDemo.higherFunDemo
object HigherFunctionV5 {
def main(args: Array[String]): Unit = {
val str1 = "Lucy"
val str2 = "@Lucy"
val res01 = str1.checkEq(str2)(eq)
println(res01)
}
/**
*函数柯里化:
* 将比较字符串分成两个任务完成:
* 1.checkEq 完成转化大小写
* 2.函数f 完成比较任务
*
**/
implicit class TestEq(s: String) {
def checkEq(ss: String)( f: (String, String) => Boolean) = {
f(s.toLowerCase,ss.toLowerCase)
}
}
def eq(s1: String, s2: String): Boolean = {
s1.equals(s2)
}
}
八、泛型
1.1 上边界
package scalaDemo.boundType
object BoundTypeV4 {
def main(args: Array[String]): Unit = {
/**
* 调用了Predef中的隐式函数:
* implicit def int2Integer(x: Int) = java.lang.Integer.valueOf(x)
* implicit def double2Double(x: Double) = java.lang.Double.valueOf(x)
* 指定泛型后,入参中的Int和Double类型通过隐式转换成了实现Comparable接口的java中的Integer和Double类型
**/
val com01 = new Compare[Integer](Integer.valueOf(2), 5)
val com02 = new Compare[java.lang.Double](6.6, 9.9)
println(com01.myCompare)
println(com02.myCompare)
}
}
/**
* 上边界:A <: B 表示A为B类型或B类型的子类
* T <: Comparable[T] 这里表示T类型是实现了Comparable接口的一个类型
* 这样传入的参数类型可以直接调用compareTo方法
**/
class Compare[T <: Comparable[T]](one: T, other: T) {
private val i: Int = one.compareTo(other)
def myCompare = if (i > 0) one else other
}
1.2 下边界
package scalaDemo.boundType
object BoundTypeV5 {
def main(args: Array[String]): Unit = {
val list01 = List(new ElecGoodsA, new PhoneA)
val list02 = List(new PhoneA, new HuaWeiPhoneA)
//info01(list01) //报错 ElecGoodsA不是PhoneA类及其子类
info01(list02)
println("***************")
/**
* 下边界:A >: B 下界比较特殊,这里A类型其实可以传入任意类型
* 传入和B有直系关系的,如果是B的父类还是按照父类处理,如果是B子类的按照B类型处理,
* 传入和B没有继承和被继承关系的,一律按照Object处理
**/
val list03 = List(new ElecGoodsA, new PhoneA, new HuaWeiPhoneA)
info02(list03).foreach(_.getInfo)
//这里ElecGoodsB和PhoneA没有直系关系,调用info02方法后:
//List[Object] = List(ElecGoodsB@3fb6a447),所以asInstanceOf转换类型后才能访问getInfo方法
val list04 = List(new ElecGoodsB)
info02(list04).map(obj => obj.asInstanceOf[ElecGoodsB].getInfo)
info02(list04).map(obj => println(obj.toString)) //scalaDemo.boundType.ElecGoodsB@3fb6a447
}
//上边界 A <: B 表示A为B类型或B类型的子类
def info01[T <: PhoneA](list: List[T]) = list.foreach(_.getInfo)
//下边界 A >: B 下界比较特殊,这里可以传入任意类型
def info02[T >: PhoneA](list: List[T]) = list
}
class ElecGoodsB {
private val message: String = "电子产品B"
def getInfo = println(message)
}
class ElecGoodsA {
private val message: String = "电子产品A"
def getInfo = println(message)
}
class PhoneA extends ElecGoodsA {
private val message: String = "手机"
override def getInfo: Unit = println(message)
}
class HuaWeiPhoneA extends PhoneA {
private val message: String = "华为手机"
override def getInfo: Unit = println(message)
}
1.3 协变和逆变
package scalaDemo.boundType
object BoundTypeV7 {
def main(args: Array[String]): Unit = {
val child = new Child08A
val father = new Father08A
child.info //Father...
//编译阶段报错:Top08A[Father08A]和Top08A[Child08A]没有继承关系
//val top01: Top08A[Father08A] = new Top08A[Child08A](child)
//协变
val top02: Top08B[Father08A] = new Top08B[Child08A](child)
//逆变
val top03: Top08C[Child08A] = new Top08C[Father08A](father)
}
}
class Father08A {
private val message = "Father..."
val job = "work..."
def info = println(message)
}
class Child08A extends Father08A {
private val message = "Child..."
override val job: String = "study..."
}
//不变
class Top08A[A](one: A) {
def getClassInfo = {
one.getClass.getName
}
}
//协变
class Top08B[+A](one: A) {
def getClassInfo = {
one.getClass.getName
}
}
class Top08C[-A](one: A) {
def getClassInfo = {
one.getClass.getName
}
}
1.4 上下文界定
1.5 视图界定
九、递归
package scalaDemo
object Fibnacci {
def main(args: Array[String]): Unit = {
println(fibn(7))
}
/**
* @Author: qwerdf@QAQ
* @Description: 斐波那契数列数列从第3项开始,每一项都等于前两项之和
* 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597 ...
* 示例: n=7 输出13
* 第1次入栈:main栈 println(fibn(7)) 最后输出:13
* 第2次 fibn1栈 fibn(7) fibn(n - 2) + fibn(n - 1) 返回9:5 + 8 = 13
* 第3次 fibn(n - 2) = fibn(5) 返回值8: 5
* fibn(n - 1) = fibn(6) 返回值7: 8
* 第4次 fibn(5 - 2) + fibn(5 - 1) = fibn(3) + fibn(4) 返回值6:2+3=5
* fibn(6 - 2) + fibn(6 - 1) = fibn(4) + fibn(5) 返回值5:3+5=8
* 第5次 f(1) + f(2) = 2
* f(2) + f(3) = 1 + f(3) 返回值4:1+2=3
* f(2) + f(3) = 1 + f(3) 返回值3:1+2=3
* f(3) + f(4) 返回值1:2+3=5
*第6次 f(1) + f(2) = 2
* f(1) + f(2) = 2
* f(1) + f(2) = 2
* f(2) + f(3) = 1 + f(3) 返回值1:1+2=3
*第7次 f(1) + f(2) = 2
*
*备注:先入栈则后出栈
*
* @Date: 2022/4/23
* @Param null:
* @return: null
**/
//递归函数编译阶段无法推断具体的结果类型,必须指定返回值类型
val fibn: Int => Int = n => {
if (n == 1 || n == 2) {
1
} else {
fibn(n - 2) + fibn(n - 1)
}
}
}
十、常用操作
1.跳出循环
package scalaDemo
import util.control.Breaks._
object CircleBreak {
def main(args: Array[String]): Unit = {
//方式1:通过调用break函数实现中断
var num1 = 0
breakable {
while (num1 <= 50) {
if (num1 % 2 != 0) {
println(s"num1==$num1")
}
if (num1 == 9) {
println("while循环中断...\r\nfor循环开始...")
break()
}
num1 += 1
}
}
breakable {
for (num2 <- 1 to 50) {
if (num2 % 2 == 0) {
println(s"num2==$num2")
}
if (num2 == 10) {
println("for循环中断...\r\n")
break()
}
}
}
//方式2:通过循环守卫实现中断
var flag = true
//def apply(start: Int, end: Int, step: Int): Range = new Range(start, end, step)
for (num3 <- Range(1, 10, 2) if flag) {
if (num3 == 5) {
flag = false
println("结束循环...")
} else {
println(s"num3==$num3")
}
}
//方式3:通过引入外部变量
val arr = Array('a','b','c','d','e','f')
var i = 0
var elem = ' '
var tmpf = true
while ({elem = arr(i); i <= arr.length && tmpf}) {
if (elem != 'd') {
println(elem)
} else {
println("结束循环...")
tmpf = false
}
i +=1
}
}
}
2.实现continue效果
package scalaDemo
object CircleContinue {
def main(args: Array[String]): Unit = {
//方式1:通过循环守卫实现continue效果
for (i <- 1 to 10 if i % 2 == 0) {
println(s"i==$i")
}
var j = 0
while (j <= 10) {
//方式2:通过if表达式实现continue效果
if (j % 2 != 0) {
println(s"j==$j")
}
j +=1
}
}
}
3.for过滤器
//for过滤器函数
val grepFunc = (books: ArrayBuffer[String], grepPattern: String) => {
if (books != null) {
val greps: ArrayBuffer[String] = for {
book <- books
if (book.contains(grepPattern))
} yield book
println(greps)
}
}
//for过滤器方法
def grep(books: ArrayBuffer[String]): ArrayBuffer[String] = {
var greps: ArrayBuffer[String] = null
if (books != null) {
greps = for {
book <- books
if (book.length == 3)
} yield book
}
greps
}
4.异常处理
package scalaDemo
import com.sun.xml.internal.bind.v2.TODO
object TryCatch {
def main(args: Array[String]): Unit = {
/**
* @Author: qwerdf@QAQ
* @Description: 将可能发生异常的代码封装在try块中,catch块用来捕获异常并处理,避免程序异常中止
* 1.在scala中只有一个catch,在java中可以有多个
* 2.在catch中有多个case,每个case匹配一种异常,即模式匹配思想。
* @Date: 2022/4/24
* @Param args:
* @return: void
**/
try {
val num = 9 / 0
} catch {
case ex: ArithmeticException => {
//TODO 捕获异常,处理业务逻辑
println("捕获了除数为零的算术异常")
}
case ex: Exception => {
//TODO 捕获异常,处理业务逻辑
println("捕获了异常")
}
} finally {
//TODO 有无异常都会执行的代码块,一般用于关闭数据库连接、IO流等
println("执行finally代码块...")
}
println("程序继续执行...")
}
}
变长参数
//变长参数
def method1(author: String, books: String*): String = {
val buffer = new StringBuffer()
var res: String = ""
if (!author.isEmpty && books != null) {
buffer.append(author + ":")
for (book <- books) {
buffer.append(book + "|")
}
val tmpStr = buffer.toString
res = tmpStr.substring(0,tmpStr.length-1)
}
res
}
//测试
val res1 = method1("古龙","武林外史","绝代双骄","楚留香传奇","多情剑客无情剑","萧十一郎","流星蝴蝶剑","边城浪子")
println(res1)
总结
未完待续…
待补充:
1.数据结构