面向对象
Scala 的面向对象思想和Java 的面向对象思想和概念是一致的。
Scala 中语法和 Java 不同,补充了更多的功能。
6.1类和对象详解
6.1.1组成结构
6.1.2构造器
每个类都有一个主构造器,这个构造器和类定义"交织"在一起类名后面的内容就是主构造器,如果参数列表为空的话,()可以省略
scala的类有且仅有一个主构造器,要想提供更加丰富的构造器,就需要使用辅助构造器,辅助构造器是可选的,它们叫做this def this
代码示例:
Scala // 类默认有一个无参的主构造函数 class User { }
val user: User = new User
// 两个参数的主构造函数 class User2(val name: String, age: Int) {
} val user2 = new User2("jim", 23) // 使用val修饰的变量默认是成员变量,对象可以访问 // user2.age // age没有使用val或者var修饰 所以不能被访问,他不是一个成员变量,而是一个局部变量
//辅助构造器 class User3 { var name: String = _ var age: Int = _ // 辅助构造函数 def this(name: String, age: Int) { // 构造函数中的首行必须调用主构造函数或者其他构造函数 this() this.name = name this.age = age } // 辅助构造函数 def this(msg: String) = { // 首行调用一个构造 this("ww", 12) println(msg) } } val u1 = new User3() val u2 = new User3("") val u3 = new User3("lisi", 23) println(u3.name) |
总结:
- 有两类构造器:主构造器,辅助构造器
- 构造器的定义位置:主构造器和类交织在一起,class Student2(val name: String, var age: Int)
- 辅助构造器是一个特殊的方法,定义在类中 def this(name:String,age:Int,gender:String)
- 辅助构造器,第一行必须调用主构造器(或者其他的辅助构造器)
- 辅助构造器的参数不能和主构造器的参数完全一致(参数个数,参数类型,参数顺序)
- 可以定义空参的辅助构造器,但是主构造器的参数必须进行初始化赋值
- 作用域:辅助构造器的变量作用域,只在方法中,主构造器的作用域是类中除了成员属性和成员方法之外的所有范围(可以通过反编译查看源码)
构造器的参数说明
- 主构造函数中使用val 和 var修饰的变量为成员变量
- val 修饰的变量默认只有getter方法 一要初始化
- var 修饰的变量默认有 get和set方法 直接点属性操作 使用 _ 占位可以稍后赋值
- @BeanProperty会生成getMsg setMsg方法
6.1.3成员方法/函数
在类的成员位置定义的函数或者方法是类的成员的一部分
6.1.4代码块
在类或者对象中的代码块在实例化的时候会被调用
- 在类成员位置的代码块 构造代码块 每次创建对象都会执行一次
- 在object中成员位置的代码块是静态代码块 只执行一次
6.1.5object类的底层原理
Scala package com.doit.day01.day02
//如果构造器中的变量,不加var 或者val 那他就是一个局部变量 //加了var 或者val 的话他就是一个私有的成员变量 class Student1(var id: Int, val name: String) {
def sayHello: Unit = { println(name + ":你好") }
val sayFunc = () => { println("hello:" + name) } }
object Student2{ var id: Int = 1 //如果在成员变量的位置上给一个_作为占位符,相当于是给他赋了一个默认值啊 var name: String =_
def sayHello: Unit = { println(name + ":你好") } val sayFunc = (x:String) => { println("hello:" + name + x) } }
object Demo01_面向对象 { def main(args: Array[String]): Unit = {
Student2.sayFunc("a")
val student1: Student1 = new Student1(1, "zhangsan") println(student1.name) println(student1.id) // student1.name = "lisi" 用val 修饰的,不能修改 student1.id = 2 println(student1.id)
student1.sayHello student1.sayFunc() println(Student2.name) } } |
java手写实现:
Java package com.doit;
public class Person { public static String getName(){ return Person$.person.getName(); }
public static Integer getAge(){ return Person$.person.getAge(); }
public static void setName(String name ){ Person$.person.setName(name); }
public static void setAge(Integer age ){ Person$.person.setAge(age); } }
class Person$ { //自己的对象 public static Person$ person ; //成员变量 private String name; private int age;
static { person = new Person$(); }
private Person$() { }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; } }
class Test{ public static void main(String[] args) { Person person = new Person(); person.setName("张三"); person.setAge(18); String name1 = person.getName(); Integer age1 = person.getAge(); System.out.println(name1); System.out.println(age1); } } |
scala中底层反编译后的代码:
Java //decompiled from Student2$.class package com.doit.day01.day02;
import java.lang.invoke.SerializedLambda; import scala.Function1; import scala.Predef.; import scala.runtime.BoxedUnit;
public final class Student2$ { public static Student2$ MODULE$; private int id; private String name; private final Function1 sayFunc;
static { new Student2$(); }
public int id() { return this.id; }
public void id_$eq(final int x$1) { this.id = x$1; }
public String name() { return this.name; }
public void name_$eq(final String x$1) { this.name = x$1; }
public void sayHello() { .MODULE$.println((new StringBuilder(3)).append(this.name()).append(":你好").toString()); }
public Function1 sayFunc() { return this.sayFunc; }
// $FF: synthetic method public static final void $anonfun$sayFunc$1(final String x) { .MODULE$.println((new StringBuilder(6)).append("hello:").append(MODULE$.name()).append(x).toString()); }
private Student2$() { MODULE$ = this; this.id = 1; this.sayFunc = (x) -> { $anonfun$sayFunc$1(x); return BoxedUnit.UNIT; }; }
// $FF: synthetic method private static Object $deserializeLambda$(SerializedLambda var0) { return var0.lambdaDeserialize<invokedynamic>(var0); } }
//decompiled from Student2.class package com.doit.day01.day02;
import scala.Function1; import scala.reflect.ScalaSignature;
@ScalaSignature( bytes = "\u0006\u0001!;Q\u0001D\u0007\t\u0002Y1Q\u0001G\u0007\t\u0002eAQ\u0001I\u0001\u0005\u0002\u0005BqAI\u0001A\u0002\u0013\u00051\u0005C\u0004(\u0003\u0001\u0007I\u0011\u0001\u0015\t\r9\n\u0001\u0015)\u0003%\u0011%y\u0013\u00011AA\u0002\u0013\u0005\u0001\u0007C\u0005=\u0003\u0001\u0007\t\u0019!C\u0001{!Iq(\u0001a\u0001\u0002\u0003\u0006K!\r\u0005\u0006\u0001\u0006!\t!\u0011\u0005\b\u0005\u0006\u0011\r\u0011\"\u0001D\u0011\u00199\u0015\u0001)A\u0005\t\u0006A1\u000b^;eK:$(G\u0003\u0002\u000f\u001f\u0005)A-Y=1e)\u0011\u0001#E\u0001\u0006I\u0006L\b'\r\u0006\u0003%M\tA\u0001Z8ji*\tA#A\u0002d_6\u001c\u0001\u0001\u0005\u0002\u0018\u00035\tQB\u0001\u0005TiV$WM\u001c;3'\t\t!\u0004\u0005\u0002\u001c=5\tADC\u0001\u001e\u0003\u0015\u00198-\u00197b\u0013\tyBD\u0001\u0004B]f\u0014VMZ\u0001\u0007y%t\u0017\u000e\u001e \u0015\u0003Y\t!!\u001b3\u0016\u0003\u0011\u0002\"aG\u0013\n\u0005\u0019b\"aA%oi\u00061\u0011\u000eZ0%KF$\"!\u000b\u0017\u0011\u0005mQ\u0013BA\u0016\u001d\u0005\u0011)f.\u001b;\t\u000f5\"\u0011\u0011!a\u0001I\u0005\u0019\u0001\u0010J\u0019\u0002\u0007%$\u0007%\u0001\u0003oC6,W#A\u0019\u0011\u0005IJdBA\u001a8!\t!D$D\u00016\u0015\t1T#\u0001\u0004=e>|GOP\u0005\u0003qq\ta\u0001\u0015:fI\u00164\u0017B\u0001\u001e<\u0005\u0019\u0019FO]5oO*\u0011\u0001\bH\u0001\t]\u0006lWm\u0018\u0013fcR\u0011\u0011F\u0010\u0005\b[\u001d\t\t\u00111\u00012\u0003\u0015q\u0017-\\3!\u0003!\u0019\u0018-\u001f%fY2|W#A\u0015\u0002\u000fM\f\u0017PR;oGV\tA\t\u0005\u0003\u001c\u000bFJ\u0013B\u0001$\u001d\u0005%1UO\\2uS>t\u0017'\u0001\u0005tCf4UO\\2!\u0001" ) public final class Student2 { public static Function1 sayFunc() { return Student2$.MODULE$.sayFunc(); }
public static void sayHello() { Student2$.MODULE$.sayHello(); }
public static void name_$eq(final String x$1) { Student2$.MODULE$.name_$eq(var0); }
public static String name() { return Student2$.MODULE$.name(); }
public static void id_$eq(final int x$1) { Student2$.MODULE$.id_$eq(var0); }
public static int id() { return Student2$.MODULE$.id(); } } |
练一练
需求1:1.定义一个object,里面放一个成员:base = 100
2.定义一个工具方法:求两数之和,如果和<base 返回和,否则返回base
3.定义一个工具函数:求两数的差,并且返回(差值<base 就返回base,否则返回差值)
4.定义一个工具函数:求三个数的最大值,如果最大值<base 就返回base,否则返回最大值
Scala object Max { val base = 100
def sum(i: Int, j: Int) = { if (i + j < base) base else i + j }
val cha = (i: Int, j: Int) => { c }
val max = (a: Int, b: Int, c: Int) => { var mx = a if (b > mx) mx = b if (c > mx) mx = c if (mx > base) mx else base } } |
需求2:用java模拟一个object内部的实现原理,把需求1这个object类模拟出来
Java //函数对应的接口 package com.doit;
public interface Function3<U,V,Y,Z> { Z apply(U u,V v,Y y); }
package com.doit;
public interface Function2<U,V,T> { T apply(U u,V v); }
//对象的.class package com.doit;
//都是放的静态的 class Max { //这里面都是静态的,用Max$里面定义的对象去调用所有的成员属性,方法和函数 private static int getBase(){ return Max$.MODULE$.getBase(); }
private static int getMax(int a,int b,int c){ return Max$.MODULE$.getMax().apply(a,b,c); }
private static int getCha(int a,int b){ return Max$.MODULE$.getCha().apply(a,b); }
private static int getSum(int a,int b){ return Max$.MODULE$.getCha().apply(a,b); }
}
//类似于java中的.class class Max$ { //还要定义一个自己的对象,对象名字是MODULE$,为了上面静态的能访问到,所以他也要是静态的 public static Max$ MODULE$; //定义成员变量,val修饰的,在java中前面要加final修饰 private final Integer base = 100; //定义两个函数 //两个数求差的函数 private final Function2<Integer, Integer, Integer> cha = new Function2<Integer, Integer, Integer>() { @Override public Integer apply(Integer integer, Integer integer2) { return integer + integer2; } };
//三个数求最大值的函数 private final Function3<Integer, Integer, Integer, Integer> max = new Function3<Integer, Integer, Integer, Integer>() { @Override public Integer apply(Integer a, Integer b, Integer c) { int mx = a; if (b > mx) mx = b; if (c > mx) mx = c; if (mx < base) mx = base; return mx; } };
//定义方法,两数求和 public int sum(int a ,int b ){ return a+b; }
//get和set方法 public int getBase(){ return base; } //base 是常量,所以这边不用写set方法 // private void setBase(int num){ // this.base = num; // }
//函数本质上也是一个类型哦,所以他也是成员变量的地位,需要写get方法哦
public Function2<Integer, Integer, Integer> getCha(){ return this.cha; }
public Function3<Integer, Integer, Integer,Integer> getMax(){ return this.max; }
static { new Max$(); }
private Max$() { MODULE$ = this; }
} |
6.1.6伴生类和伴生对象
条件 1:在同一个源文件中, 条件 2:对象名和类名相同
Scala //类名和object的名称一致 //类是对象的伴生类 //对象是类的伴生对象
class Demo6(val name: String) { } object Demo6 { } |
条件 2:伴生对象和伴生类之间可以互相访问彼此的私有属性和私有方法
Scala package com.doit.day01.day02
/** * 伴生对象的用途: * 1.可以将静态的成员变量和普通成员变量分别声明 * 2.伴生对象自己内部定义了一个apply方法,可以简化创建对象(类的实例构造) * 3.伴生对象自己定义了一个unapply方法,可以用于模式匹配 */ class Car(var brand: String, var price: Double) {
def sayHello(): Unit ={ println("hello") }
private val color: String = Car.color Car.start() }
object Car { var color :String = "red"
def start(): Unit ={ println("汽车启动了,嗡~~~~~~~~") } }
object Demo02_伴生对象 { def main(args: Array[String]): Unit = { val car: Car = new Car("华为", 9.9) println(car.brand) println(car.price) car.sayHello() Car.start() } } |
伴生对象的底层原理:
Java //decompiled from Car.class package com.doit.day01.day02;
import scala.Predef.; import scala.reflect.ScalaSignature;
@ScalaSignature( bytes = "\u0006\u0001E3A\u0001E\t\u00015!A\u0011\u0005\u0001BA\u0002\u0013\u0005!\u0005\u0003\u0005/\u0001\t\u0005\r\u0011\"\u00010\u0011!)\u0004A!A!B\u0013\u0019\u0003\u0002\u0003\u001c\u0001\u0005\u0003\u0007I\u0011A\u001c\t\u0011m\u0002!\u00111A\u0005\u0002qB\u0001B\u0010\u0001\u0003\u0002\u0003\u0006K\u0001\u000f\u0005\u0006\u007f\u0001!\t\u0001\u0011\u0005\u0006\u000b\u0002!\tAR\u0004\u0006\u000fFA\t\u0001\u0013\u0004\u0006!EA\t!\u0013\u0005\u0006\u007f)!\tA\u0013\u0005\b\u0017*\u0001\r\u0011\"\u0001#\u0011\u001da%\u00021A\u0005\u00025Caa\u0014\u0006!B\u0013\u0019\u0003\"\u0002)\u000b\t\u00031%aA\"be*\u0011!cE\u0001\u0006I\u0006L\bG\r\u0006\u0003)U\tQ\u0001Z1zaER!AF\f\u0002\t\u0011|\u0017\u000e\u001e\u0006\u00021\u0005\u00191m\\7\u0004\u0001M\u0011\u0001a\u0007\t\u00039}i\u0011!\b\u0006\u0002=\u0005)1oY1mC&\u0011\u0001%\b\u0002\u0007\u0003:L(+\u001a4\u0002\u000b\t\u0014\u0018M\u001c3\u0016\u0003\r\u0002\"\u0001J\u0016\u000f\u0005\u0015J\u0003C\u0001\u0014\u001e\u001b\u00059#B\u0001\u0015\u001a\u0003\u0019a$o\\8u}%\u0011!&H\u0001\u0007!J,G-\u001a4\n\u00051j#AB*ue&twM\u0003\u0002+;\u0005I!M]1oI~#S-\u001d\u000b\u0003aM\u0002\"\u0001H\u0019\n\u0005Ij\"\u0001B+oSRDq\u0001\u000e\u0002\u0002\u0002\u0003\u00071%A\u0002yIE\naA\u0019:b]\u0012\u0004\u0013!\u00029sS\u000e,W#\u0001\u001d\u0011\u0005qI\u0014B\u0001\u001e\u001e\u0005\u0019!u.\u001e2mK\u0006I\u0001O]5dK~#S-\u001d\u000b\u0003auBq\u0001N\u0003\u0002\u0002\u0003\u0007\u0001(\u0001\u0004qe&\u001cW\rI\u0001\u0007y%t\u0017\u000e\u001e \u0015\u0007\u0005\u001bE\t\u0005\u0002C\u00015\t\u0011\u0003C\u0003\"\u000f\u0001\u00071\u0005C\u00037\u000f\u0001\u0007\u0001(\u0001\u0005tCfDU\r\u001c7p)\u0005\u0001\u0014aA\"beB\u0011!IC\n\u0003\u0015m!\u0012\u0001S\u0001\u0006G>dwN]\u0001\nG>dwN]0%KF$\"\u0001\r(\t\u000fQj\u0011\u0011!a\u0001G\u000511m\u001c7pe\u0002\nQa\u001d;beR\u0004" ) public class Car { private String brand; private double price;
public static void start() { Car$.MODULE$.start(); }
public static void color_$eq(final String x$1) { Car$.MODULE$.color_$eq(var0); }
public static String color() { return Car$.MODULE$.color(); }
public String brand() { return this.brand; }
public void brand_$eq(final String x$1) { this.brand = x$1; }
public double price() { return this.price; }
public void price_$eq(final double x$1) { this.price = x$1; }
public void sayHello() { .MODULE$.println("hello"); }
public Car(final String brand, final double price) { this.brand = brand; this.price = price; super(); } }
//decompiled from Car$.class package com.doit.day01.day02;
import scala.Predef.;
public final class Car$ { public static Car$ MODULE$; private String color;
static { new Car$(); }
public String color() { return this.color; }
public void color_$eq(final String x$1) { this.color = x$1; }
public void start() { .MODULE$.println("汽车启动了,嗡~~~~~~~~"); }
private Car$() { MODULE$ = this; this.color = "red"; } }
|
图示:
伴生对象用途:
- 可以将静态的成员变量和普通成员变量分别声明(class中没办法添加静态成员,需要经过object类来添加)
- 伴生对象自己内部定义了一个apply方法,可以简化创建对象(类的实例构造)
- 伴生对象自己定义了一个unapply方法,可以用于模式匹配
6.1.6apply方法
使用此方法时,可以在main函数中不通过new来创建一个对象,即可以不用专门的一次一次地进行实例化,加载创建对象的这个类的时候,会自动调用apply这个方法,类似Java中的static静态块。
- 通过伴生对象的 apply 方法,实现不使用 new 方法创建对象。
- apply 方法可以重载。
- Scala 中 obj(arg)的语句实际是在调用该对象的 apply 方法,即 obj.apply(arg)。用以统一面向对象编程和函数式编程的风格。
- 当使用 new 关键字构建对象时,调用的其实是类的构造方法,当直接使用类名构建对象时,调用的其实是伴生对象的 apply 方法。
Scala object Test { def main(args: Array[String]): Unit = { //(1)通过伴生对象的 apply 方法,实现不使用 new 关键字创建对象。 val p1 = Person() println("p1.name=" + p1.name) val p2 = Person("bobo") println("p2.name=" + p2.name) } } //(2)如果想让主构造器变成私有的,可以在()之前加上 private class Person private(cName: String) { var name: String = cName }
object Person { def apply(): Person = { println("apply 空参被调用") new Person("xx") } def apply(name: String): Person = { println("apply 有参被调用") new Person(name) } } |
6.2权限修饰符
在 Java 中,访问权限分为:public,private,protected 和默认。在 Scala 中,你可以通过类似的修饰符达到同样的效果。但是使用上有区别。
(1)Scala 中属性和方法的默认访问权限为 public,但 Scala 中无 public 关键字。
(2)private 为私有权限,只在类的内部和伴生对象中可用。
(3)protected 为受保护权限,Scala 中受保护权限比 Java 中更严格,同类、子类可以访问,同包无法访问。
(4)private[包名]增加包访问权限,包名下的其他类也可以使用
代码演示:
Scala class Person { private var name: String = "bobo" protected var age: Int = 18 private[test] var sex: String = "男" def say(): Unit = { println(name) } } object Person { def main(args: Array[String]): Unit = { val person = new Person person.say() println(person.name) println(person.age) } } class Teacher extends Person { def test(): Unit = { this.age this.sex } } class Animal { def test: Unit = { new Person().sex } } |
6.3特质和抽象类
6.3.1特质
Trait(特质)相当于 java 的接口。比接口功能更强大。特质中可以定义属性和抽象方法和方法的实现。
Scala 的类只能够继承单一父类,但是可以实现(继承,混入)多个特质(Trait),使用的关键字是 with 和 extends
基本语法
Scala trait 特质名 { trait 主体 }
//如何使用特质: 没有父类:class 类名 extends 特质 1 with 特质 2 with 特质 3 … 有父类:class 类名 extends 父类 with 特质 1 with 特质 2 with 特质 3… |
代码演示:
Scala trait PersonTrait { // 声明属性 var name:String = _ // 声明方法 def eat():Unit={ } // 抽象属性 var age:Int // 抽象方法 def say():Unit } |
6.3.1.2特质的动态混入
1.创建对象时混入 trait,而无需使类混入该 trait
2.如果混入的 trait 中有未实现的方法,则需要实现
代码演示:
Scala trait PersonTrait { //(1)特质可以同时拥有抽象方法和具体方法 // 声明属性 var name: String = _ // 抽象属性 var age: Int // 声明方法 def eat(): Unit = { println("eat") } // 抽象方法 def say(): Unit } trait SexTrait { var sex: String } //(2)一个类可以实现/继承多个特质 //(3)所有的 Java 接口都可以当做 Scala 特质使用 class Teacher extends PersonTrait with java.io.Serializable { override def say(): Unit = { println("say") } override var age: Int = _ } object TestTrait { def main(args: Array[String]): Unit = { val teacher = new Teacher teacher.say() teacher.eat() //(4)动态混入:可灵活的扩展类的功能 val t2 = new Teacher with SexTrait { override var sex: String = "男" } //调用混入 trait 的属性 println(t2.sex) } } |
6.3.2抽象类
在 Scala 中, 使用 abstract 修饰的类称为抽象类. 在抽象类中可以定义属性、未实现的方法(抽象方法)和具体实现的方法。 含有抽象方法的类就是抽象类
示例:
Scala /* * abstract 修饰的类是一个抽象类 * */ abstract class Animal { println("Animal's constructor ....") // 定义一个 name 属性 val name: String = "animal" // 没有任何实现的方法 def sleep() // 带有具体的实现的方法 def eat(f: String): Unit = { println(s"$f") } } |
抽象类的继承和重写
- 如果父类为抽象类,那么子类要么也是抽象类,要么就需要重写父类中的所有的抽象方法和抽象的成员变量
- 重写非抽象方法需要用 override 修饰,重写抽象方法则可以不加 override。
- 子类中调用父类的方法使用 super 关键字,在子类重写了父类的方法后,如果不加super,直接写方法名调用的就是子类重写后的,如果加了,调用的还是父类的
- 子类对抽象属性进行实现,父类抽象属性可以用 var 修饰;子类对非抽象属性重写,父类非抽象属性只支持 val 类型,而不支持 var(var修饰具体方法和变量不好重写)
因为 var 修饰的为可变变量,子类继承之后就可以直接使用,没有必要重写 |
6.4样例类
使用case修饰的类就是样例类(封装数据,模式匹配)
- 构造器中的参数默认是val修饰的[成员,赋值1次]
- 样例类会自动创建伴生对象, 同时在里面实现;的apply和unapply方法 ,创建对象的时候不用new
- 很好的支持匹配模式
- 默认实现了自己的toString , hashCode , copy , equals,序列化方法
定义一个样例类:
Scala case class Person(var name:String , var age:Int) {}//如果类中没有别的需要定义的,可以不写大括号 |
反编译之后的结果:
Scala //decompiled from Person$.class package com.doit.day01.day02;
import scala.Option; import scala.Serializable; import scala.Some; import scala.Tuple2; import scala.None.; import scala.runtime.AbstractFunction2; import scala.runtime.BoxesRunTime;
public final class Person$ extends AbstractFunction2 implements Serializable { public static Person$ MODULE$;
static { new Person$(); }
public final String toString() { return "Person"; }
public Person apply(final String name, final int age) { return new Person(name, age); }
public Option unapply(final Person x$0) { return (Option)(x$0 == null ? .MODULE$ : new Some(new Tuple2(x$0.name(), BoxesRunTime.boxToInteger(x$0.age())))); }
private Object readResolve() { return MODULE$; }
// $FF: synthetic method // $FF: bridge method public Object apply(final Object v1, final Object v2) { return this.apply((String)v1, BoxesRunTime.unboxToInt(v2)); }
private Person$() { MODULE$ = this; } }
//decompiled from Person.class package com.doit.day01.day02;
import scala.Function1; import scala.Option; import scala.Product; import scala.Serializable; import scala.collection.Iterator; import scala.reflect.ScalaSignature; import scala.runtime.BoxesRunTime; import scala.runtime.Statics; import scala.runtime.ScalaRunTime.;
@ScalaSignature( bytes = "\u0006\u0001\u0005Uc\u0001\u0002\u000e\u001c\u0001\u0012B\u0001\"\r\u0001\u0003\u0012\u0004%\tA\r\u0005\t}\u0001\u0011\t\u0019!C\u0001\u007f!AQ\t\u0001B\tB\u0003&1\u0007\u0003\u0005G\u0001\tE\r\u0011\"\u0001H\u0011!Y\u0005A!a\u0001\n\u0003a\u0005\u0002\u0003(\u0001\u0005#\u0005\u000b\u0015\u0002%\t\u000b=\u0003A\u0011\u0001)\t\u000fU\u0003\u0011\u0011!C\u0001-\"9\u0011\fAI\u0001\n\u0003Q\u0006bB3\u0001#\u0003%\tA\u001a\u0005\bQ\u0002\t\t\u0011\"\u0011j\u0011\u001d\t\b!!A\u0005\u0002\u001dCqA\u001d\u0001\u0002\u0002\u0013\u00051\u000fC\u0004y\u0001\u0005\u0005I\u0011I=\t\u0013\u0005\u0005\u0001!!A\u0005\u0002\u0005\r\u0001\"CA\u0007\u0001\u0005\u0005I\u0011IA\b\u0011%\t\t\u0002AA\u0001\n\u0003\n\u0019\u0002C\u0005\u0002\u0016\u0001\t\t\u0011\"\u0011\u0002\u0018\u001dI\u00111D\u000e\u0002\u0002#\u0005\u0011Q\u0004\u0004\t5m\t\t\u0011#\u0001\u0002 !1q\n\u0006C\u0001\u0003[A\u0011\"!\u0005\u0015\u0003\u0003%)%a\u0005\t\u0013\u0005=B#!A\u0005\u0002\u0006E\u0002\"CA\u001c)\u0005\u0005I\u0011QA\u001d\u0011%\tY\u0005FA\u0001\n\u0013\tiE\u0001\u0004QKJ\u001cxN\u001c\u0006\u00039u\tQ\u0001Z1zaIR!AH\u0010\u0002\u000b\u0011\f\u0017\u0010M\u0019\u000b\u0005\u0001\n\u0013\u0001\u00023pSRT\u0011AI\u0001\u0004G>l7\u0001A\n\u0005\u0001\u0015Zc\u0006\u0005\u0002'S5\tqEC\u0001)\u0003\u0015\u00198-\u00197b\u0013\tQsE\u0001\u0004B]f\u0014VM\u001a\t\u0003M1J!!L\u0014\u0003\u000fA\u0013x\u000eZ;diB\u0011aeL\u0005\u0003a\u001d\u0012AbU3sS\u0006d\u0017N_1cY\u0016\fAA\\1nKV\t1\u0007\u0005\u00025w9\u0011Q'\u000f\t\u0003m\u001dj\u0011a\u000e\u0006\u0003q\r\na\u0001\u0010:p_Rt\u0014B\u0001\u001e(\u0003\u0019\u0001&/\u001a3fM&\u0011A(\u0010\u0002\u0007'R\u0014\u0018N\\4\u000b\u0005i:\u0013\u0001\u00038b[\u0016|F%Z9\u0015\u0005\u0001\u001b\u0005C\u0001\u0014B\u0013\t\u0011uE\u0001\u0003V]&$\bb\u0002#\u0003\u0003\u0003\u0005\raM\u0001\u0004q\u0012\n\u0014!\u00028b[\u0016\u0004\u0013aA1hKV\t\u0001\n\u0005\u0002'\u0013&\u0011!j\n\u0002\u0004\u0013:$\u0018aB1hK~#S-\u001d\u000b\u0003\u00016Cq\u0001R\u0003\u0002\u0002\u0003\u0007\u0001*\u0001\u0003bO\u0016\u0004\u0013A\u0002\u001fj]&$h\bF\u0002R'R\u0003\"A\u0015\u0001\u000e\u0003mAQ!M\u0004A\u0002MBQAR\u0004A\u0002!\u000bAaY8qsR\u0019\u0011k\u0016-\t\u000fEB\u0001\u0013!a\u0001g!9a\t\u0003I\u0001\u0002\u0004A\u0015AD2paf$C-\u001a4bk2$H%M\u000b\u00027*\u00121\u0007X\u0016\u0002;B\u0011alY\u0007\u0002?*\u0011\u0001-Y\u0001\nk:\u001c\u0007.Z2lK\u0012T!AY\u0014\u0002\u0015\u0005tgn\u001c;bi&|g.\u0003\u0002e?\n\tRO\\2iK\u000e\\W\r\u001a,be&\fgnY3\u0002\u001d\r|\u0007/\u001f\u0013eK\u001a\fW\u000f\u001c;%eU\tqM\u000b\u0002I9\u0006i\u0001O]8ek\u000e$\bK]3gSb,\u0012A\u001b\t\u0003WBl\u0011\u0001\u001c\u0006\u0003[:\fA\u0001\\1oO*\tq.\u0001\u0003kCZ\f\u0017B\u0001\u001fm\u00031\u0001(o\u001c3vGR\f%/\u001b;z\u00039\u0001(o\u001c3vGR,E.Z7f]R$\"\u0001^<\u0011\u0005\u0019*\u0018B\u0001<(\u0005\r\te.\u001f\u0005\b\t6\t\t\u00111\u0001I\u0003=\u0001(o\u001c3vGRLE/\u001a:bi>\u0014X#\u0001>\u0011\u0007mtH/D\u0001}\u0015\tix%\u0001\u0006d_2dWm\u0019;j_:L!a ?\u0003\u0011%#XM]1u_J\f\u0001bY1o\u000bF,\u0018\r\u001c\u000b\u0005\u0003\u000b\tY\u0001E\u0002'\u0003\u000fI1!!\u0003(\u0005\u001d\u0011un\u001c7fC:Dq\u0001R\b\u0002\u0002\u0003\u0007A/\u0001\u0005iCND7i\u001c3f)\u0005A\u0015\u0001\u0003;p'R\u0014\u0018N\\4\u0015\u0003)\fa!Z9vC2\u001cH\u0003BA\u0003\u00033Aq\u0001\u0012\n\u0002\u0002\u0003\u0007A/\u0001\u0004QKJ\u001cxN\u001c\t\u0003%R\u0019B\u0001FA\u0011]A9\u00111EA\u0015g!\u000bVBAA\u0013\u0015\r\t9cJ\u0001\beVtG/[7f\u0013\u0011\tY#!\n\u0003#\u0005\u00137\u000f\u001e:bGR4UO\\2uS>t'\u0007\u0006\u0002\u0002\u001e\u0005)\u0011\r\u001d9msR)\u0011+a\r\u00026!)\u0011g\u0006a\u0001g!)ai\u0006a\u0001\u0011\u00069QO\\1qa2LH\u0003BA\u001e\u0003\u000f\u0002RAJA\u001f\u0003\u0003J1!a\u0010(\u0005\u0019y\u0005\u000f^5p]B)a%a\u00114\u0011&\u0019\u0011QI\u0014\u0003\rQ+\b\u000f\\33\u0011!\tI\u0005GA\u0001\u0002\u0004\t\u0016a\u0001=%a\u0005Y!/Z1e%\u0016\u001cx\u000e\u001c<f)\t\ty\u0005E\u0002l\u0003#J1!a\u0015m\u0005\u0019y%M[3di\u0002" ) public class Person implements Product, Serializable { private String name; private int age;
public static Option unapply(final Person x$0) { return Person$.MODULE$.unapply(var0); }
public static Person apply(final String name, final int age) { return Person$.MODULE$.apply(var0, var1); }
public static Function1 tupled() { return Person$.MODULE$.tupled(); }
public static Function1 curried() { return Person$.MODULE$.curried(); }
public String name() { return this.name; }
public void name_$eq(final String x$1) { this.name = x$1; }
public int age() { return this.age; }
public void age_$eq(final int x$1) { this.age = x$1; }
public Person copy(final String name, final int age) { return new Person(name, age); }
public String copy$default$1() { return this.name(); }
public int copy$default$2() { return this.age(); }
public String productPrefix() { return "Person"; }
public int productArity() { return 2; }
public Object productElement(final int x$1) { Object var10000; switch(x$1) { case 0: var10000 = this.name(); break; case 1: var10000 = BoxesRunTime.boxToInteger(this.age()); break; default: throw new IndexOutOfBoundsException(BoxesRunTime.boxToInteger(x$1).toString()); }
return var10000; }
public Iterator productIterator() { return .MODULE$.typedProductIterator(this); }
public boolean canEqual(final Object x$1) { return x$1 instanceof Person; }
public int hashCode() { int var1 = -889275714; var1 = Statics.mix(var1, Statics.anyHash(this.name())); var1 = Statics.mix(var1, this.age()); return Statics.finalizeHash(var1, 2); }
public String toString() { return .MODULE$._toString(this); }
public boolean equals(final Object x$1) { boolean var6; if (this != x$1) { label55: { boolean var2; if (x$1 instanceof Person) { var2 = true; } else { var2 = false; }
if (var2) { label38: { label37: { Person var4 = (Person)x$1; String var10000 = this.name(); String var5 = var4.name(); if (var10000 == null) { if (var5 != null) { break label37; } } else if (!var10000.equals(var5)) { break label37; }
if (this.age() == var4.age() && var4.canEqual(this)) { var6 = true; break label38; } }
var6 = false; }
if (var6) { break label55; } }
var6 = false; return var6; } }
var6 = true; return var6; }
public Person(final String name, final int age) { this.name = name; this.age = age; super(); Product.$init$(this); } } |
case class 和 class 的一些区别:
- case class 在初始化的时候,不用 new,而普通类初始化时必须要 new。
- case class 重写了 toString 方法。 默认实现了 equals 和 hashCode
- case class 实现了序列化接口 with Serializable
- case class 支持模式匹配(最重要的特征),所有 case class 必须要有参数列表
- 有参数用 case class,无参用 case object
6.5继承和多态
基本语法
class 子类名 extends 父类名 { 类体 }
(1)子类继承父类的属性和方法
(2)scala 是单继承
案例实操:
(1)子类继承父类的属性和方法
(2)继承的调用顺序:父类构造器->子类构造器
Scala class Person(nameParam: String) { var name = nameParam var age: Int = _ def this(nameParam: String, ageParam: Int) { this(nameParam) this.age = ageParam println("父类辅助构造器") } println("父类主构造器") } class Emp(nameParam: String, ageParam: Int) extends Person(nameParam, ageParam) { var empNo: Int = _ def this(nameParam: String, ageParam: Int, empNoParam: Int) { this(nameParam, ageParam) this.empNo = empNoParam println("子类的辅助构造器") } println("子类主构造器") } object Test { def main(args: Array[String]): Unit = { new Emp("z3", 11,1001) } } |
练一练:
定义一个order类 属性:user_id , order_id,goods_id,category_id,price,goods_num 需求1:对10个订单的金额大小的升序排列 需求2:对10个订单的金额大小的降序排列 需求3:统计每一种品类下的订单总额 需求4:统计每一个用户的订单总额 需求5:找出每个用户金额最大的哪个订单 需求6:找出每一种品类中金额最大的订单 需求7:找出订单金额最大的两个订单 需求8:找出订单金额最小的两个订单 |
第 7 章 集合
scala中的集合分为两种 ,可变集合和不可变集合, 不可变集合可以安全的并发的访问!
集合的类主要在一下两个包中
- 可变集合包 scala.collection.mutable
- 不可变集合包 scala.collection.immutable 默认的
Scala 不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而不会对原对象进行修改。类似于 java 中的 String 对象 可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似于 java 中 StringBuilder 对象 建议:在操作集合的时候,不可变用符号,可变用方法 |
scala默认使用的是不可变的集合 , 因此使用可变的集合需要导入可变集合的包
scala的集合主要分成三大类
- Seq 序列
- Set 不重复集
- Map 键值映射集
注意: 所有的集合都继承自Iterator迭代器这个特质 |
不可变集合继承图
7.1迭代器(重点)
7.1.1java中的iterator
在java中用迭代器读取文件中的数据,每次返回一行数据
Java package com.doit;
import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.Iterator;
class MyHero implements Iterator<String> { BufferedReader buffer = null; String line = null;
public MyHero() { try { buffer = new BufferedReader(new FileReader("data/hero.txt")); } catch (FileNotFoundException e) { e.printStackTrace(); } }
@Override public boolean hasNext() { try { line = buffer.readLine(); } catch (IOException e) { e.printStackTrace(); } return line != null; }
@Override public String next() { return line; } }
public class MyIterator{ public static void main(String[] args) { MyHero myHero = new MyHero(); while (myHero.hasNext()){ System.out.println(myHero.next()); } } } |
在java中用迭代器读取mysql表中的数据,每次返回一行数据
Java package com.doit;
import java.sql.*; import java.util.Iterator;
public class ReadTable implements Iterator<Login> { ResultSet resultSet = null; public ReadTable(){ try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } try { Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/football", "root", "123456"); PreparedStatement pps = conn.prepareStatement("select * from login "); resultSet = pps.executeQuery(); } catch (SQLException e) { e.printStackTrace(); } }
@Override public boolean hasNext() { boolean flag = false; try { flag = resultSet.next(); } catch (SQLException e) { e.printStackTrace(); } return flag; }
@Override public Login next() { Login login = new Login(); try { login.setId(resultSet.getInt(1)); login.setUser_id(resultSet.getInt(2)); login.setClient_id(resultSet.getInt(3)); login.setDate(resultSet.getString(4)); } catch (SQLException e) { e.printStackTrace(); } return login; }
}
class Login { private int id; private int user_id; private int client_id; private String date;
public Login() { }
public Login(int id, int user_id, int client_id, String date) { this.id = id; this.user_id = user_id; this.client_id = client_id; this.date = date; }
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public int getUser_id() { return user_id; }
public void setUser_id(int user_id) { this.user_id = user_id; }
public int getClient_id() { return client_id; }
public void setClient_id(int client_id) { this.client_id = client_id; }
public String getDate() { return date; }
public void setDate(String date) { this.date = date; }
@Override public String toString() { return "login{" + "id=" + id + ", user_id=" + user_id + ", client_id=" + client_id + ", date='" + date + '\'' + '}'; } } |
7.1.2java中的Iterable
代表可迭代的,返回的是一个迭代器
Java package com.doit;
import java.util.Iterator;
public class ReadTableIterable implements Iterable<Login>{ @Override public Iterator iterator() { return new ReadTable(); } }
//测试 package com.doit;
import java.util.Iterator;
public class Test3 { public static void main(String[] args) { ReadTableIterable logins = new ReadTableIterable(); //可迭代的都会有一个迭代器对象,获取出来后用hasnext next获取数据 Iterator iterator = logins.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } //可迭代的java底层都封装了增强for循环,也可以直接使用 for (Login login : logins) { System.out.println(login); } } } |
7.1.3scala中的 iterator
Scala package com.doit.day01.day02
import scala.io.{BufferedSource, Source}
object MyIter { def main(args: Array[String]): Unit = { val iter: MyIter = new MyIter while (iter.hasNext){ println(iter.next()) } }
}
class MyIter extends Iterator[String]{ //读取数据 private val source: BufferedSource = Source.fromFile("data/hero.txt") private val lines: Iterator[String] = source.getLines() //用scala中返回迭代器中的hasNext方法直接判断 override def hasNext: Boolean = lines.hasNext //用scala中返回迭代器中的next方法获取数据 override def next(): String = lines.next() } |
7.1.4scala中的Iterable
Scala package com.doit.day01.day02
import scala.io.{BufferedSource, Source}
object MyIter { def main(args: Array[String]): Unit = { val iter: MyIter1 = new MyIter1 val iterator: Iterator[String] = iter.iterator while (iterator.hasNext){ println(iterator.next()) }
for (elem <- iter) { println(elem) } } }
class MyIter1 extends Iterable[String]{ override def iterator: Iterator[String] = new MyIter } |
7.2比较器
7.2.1java中的比较器 Comparator
Java package com.doit;
import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator;
public class Test3 { public static void main(String[] args) { Order or1 = new Order("001", 100, "2022-7-12"); Order or2 = new Order("002", 99, "2022-7-11"); Order or3 = new Order("003", 88, "2022-7-15"); Order or4 = new Order("004", 103, "2022-7-13"); Order or5 = new Order("005", 55, "2022-7-10");
ArrayList<Order> list = new ArrayList<>(); list.add(or1); list.add(or2); list.add(or3); list.add(or4); list.add(or5); Collections.sort(list,new ComparatorDeme()); System.out.println(list); Collections.sort(list,new ComparatorDeme1()); System.out.println(list); } }
class ComparatorDeme implements Comparator<Order>{
@Override public int compare(Order o1, Order o2) { return -o1.getOrderAmount() + o2.getOrderAmount(); } }
class ComparatorDeme1 implements Comparator<Order>{
@Override public int compare(Order o1, Order o2) { return o1.getOrderTime().compareTo(o2.getOrderTime()); } } |
7.2.2java中的比较器 Comparable
Java package com.doit; //类实现Comparable 接口,重写里面的compareTo 方法 public class Order2 implements Comparable<Order2>{ private String orderId; private int orderAmount; private String orderTime;
public Order2() { }
public Order2(String orderId, int orderAmount, String orderTime) { this.orderId = orderId; this.orderAmount = orderAmount; this.orderTime = orderTime; }
public String getOrderId() { return orderId; }
public void setOrderId(String orderId) { this.orderId = orderId; }
public int getOrderAmount() { return orderAmount; }
public void setOrderAmount(int orderAmount) { this.orderAmount = orderAmount; }
public String getOrderTime() { return orderTime; }
public void setOrderTime(String orderTime) { this.orderTime = orderTime; }
@Override public String toString() { return "Order{" + "orderId='" + orderId + '\'' + ", orderAmount=" + orderAmount + ", orderTime='" + orderTime + '\'' + '}'; }
@Override public int compareTo(Order2 o) { return this.orderAmount - o.orderAmount; } }
package com.doit;
import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator;
public class Test3 { public static void main(String[] args) { // Order or1 = new Order("001", 100, "2022-7-12"); // Order or2 = new Order("002", 99, "2022-7-11"); // Order or3 = new Order("003", 88, "2022-7-15"); // Order or4 = new Order("004", 103, "2022-7-13"); // Order or5 = new Order("005", 55, "2022-7-10"); // // ArrayList<Order> list = new ArrayList<>(); // list.add(or1); // list.add(or2); // list.add(or3); // list.add(or4); // list.add(or5); // Collections.sort(list,new ComparatorDeme()); // System.out.println(list); // Collections.sort(list,new ComparatorDeme1()); // System.out.println(list); // System.out.println("===========华丽的分割线==========");
Order2 o1 = new Order2("001", 100, "2022-7-12"); Order2 o2 = new Order2("002", 99, "2022-7-11"); Order2 o3 = new Order2("003", 88, "2022-7-15"); Order2 o4 = new Order2("004", 103, "2022-7-13"); Order2 o5 = new Order2("005", 55, "2022-7-10");
ArrayList<Order2> list1 = new ArrayList<>(); list1.add(o1); list1.add(o2); list1.add(o3); list1.add(o4); list1.add(o5); //这边就不需要再传入比较器了 Collections.sort(list1); System.out.println(list1); } } |
7.2.3scala中的比较器 Ordering 类比于java中的Comparator
Scala package com.doit.day01.day02
import scala.util.Sorting object Demo_Ordering { def main(args: Array[String]): Unit = { val e1: Employee = new Employee(1, "涛哥", 10000) val e2: Employee = new Employee(2, "星哥", 8000) val e3: Employee = new Employee(3, "行哥", 5000) val e4: Employee = new Employee(4, "源哥", 3500) val e5: Employee = new Employee(5, "娜姐", 2000) val list: Array[Employee] = List(e1, e2, e3, e4, e5).toArray Sorting.quickSort(list)(MyOrdering()) println(list.mkString(","))
} } case class MyOrdering() extends Ordering[Employee] { override def compare(x: Employee, y: Employee): Int = (x.salary - y.salary).toInt }
class Employee(val id:Int,val name:String,val salary:Double) override def toString = s"Employee(id=$id, name=$name, salary=$salary)" } |
7.2.4scala中的比较器 Ordered 类比于java中的Comparable
Scala package com.doit.day01.day02
import scala.util.Sorting
object Demo_Ordering { def main(args: Array[String]): Unit = { val e1: Employee = new Employee(1, "涛哥", 10000) val e2: Employee = new Employee(2, "星哥", 8000) val e3: Employee = new Employee(3, "行哥", 5000) val e4: Employee = new Employee(4, "源哥", 3500) val e5: Employee = new Employee(5, "娜姐", 2000) val list: Array[Employee] = List(e1, e2, e3, e4, e5).toArray Sorting.quickSort(list) println(list.mkString(",")) } }
class Employee(val id:Int,val name:String,val salary:Double) extends Ordered[Employee]{
override def toString = s"Employee(id=$id, name=$name, salary=$salary)"
override def compare(that: Employee): Int = (this.salary - that.salary).toInt } |