1. Java是面向对象的编程语言,由于历史原因,Java中还存在着非面向对象的内容:基本类型 ,null,
静态方法等;
2. Scala语言来自于Java,所以天生就是面向对象的语言,而且Scala是纯粹的面向对象的语言,即在
Scala中,一切皆为对象。
面向对象解决养猫的问题示例代码:
package com.lj.scala.obj
/**
* @author Administrator
* @create 2020-03-10
*/
object ObjTest01 {
def main(args: Array[String]): Unit = {
val cat = new Cat
cat.age = 2
cat.name = "闪电"
cat.color = "白色"
printf("他家宠物猫的信息:
\n年龄:%s,\n名字:%s,\n颜色:%s.\n", cat.age, cat.name, cat.color)
}
}
class Cat {
/**
* 说明:
* 1. 当我们声明了var name: String时,在底层对应的是private name;
* 2. 同时会生成两个public方法name() 相当于Java中getter方法,另一个是name_$eq()
* 相当于Java中的setter方法。
*/
// 定义/声明三个属性
var name: String = "" // 给初始值
var age: Int = _ // "_" 下划线表示age一个默认值,如果Int默认是0
var color: String = _ // "_" 表示给color默认值,如果是String,默认是""
}
========================运行结果=============================
他家宠物猫的信息:
年龄:2,
名字:闪电,
颜色:白色.
========================运行结果=============================
通过上面的案例可以得出结论
1. 类是抽象的,概念的,代表一类事物,比如人类,猫类...;
2. 对象是具体的,实际的,代表一个具体事物;
3. 类是对象的模板,对象是类的一个个体,对应一个实例;
4. Scala中类和对象的区别和联系和Java是一样的。
基本语法
[修饰符] class 类名 {
类体
}
定义类的注意事项
1. scala语法中,类并不声明为public,所有这些类都具有公有可见性(即默认就是public);
2. 一个Scala源文件可以包含多个类。
介绍
属性是类的一个组成部分,一般是值数据类型,也可是引用类型。比如前面定义猫类的age就是属性。
注意事项和细节说明
1. 属性的定义语法同变量,示例:[访问修饰符] var 属性名称 [:类型] = 属性值;
2. 属性的定义类型可以为任意类型,包含值类型或引用类型;
3. Scala中声明一个属性,必须显示的初始化,然后根据初始化数据的类型自动推断,属性类型可以省略(这点和Java不同);
4. 如果赋值为null,则一定要加类型,因为不加类型, 那么该属性的类型就是Null类型;
5. 如果在定义属性时,暂时不赋值,也可以使用符号_(下划线),让系统分配默认值;
6. 不同对象的属性是独立,互不影响,一个对象对属性的更改,不影响另外一个(这点和java完全一样)。
基本语法
val | var 对象名 [:类型] = new 类型()
注意事项
1. 如果我们不希望改变对象的引用(即:内存地址), 应该声明为val性质的对象,否则声明为var性质的
对象。 Scala设计者推荐使用val ,因为一般来说,在程序中,我们只是改变对象属性的值,而不是改变
对象的引用;
2. Scala在声明对象变量时,可以根据创建对象的类型自动推断,所以类型声明可以省略,但当类型和
后面new对象类型有继承关系即多态时,就必须写了。
示例代码:
package com.lj.scala.obj
/**
* @author Administrator
* @create 2020-03-10
*/
class ObjTest02 {
def main(args: Array[String]): Unit = {
val stu01 = new Student
// 如果此时希望将子类对象交给父类对象的引用,这时就需要写上类型
val stu02: Person = new Person
/**
* 可以发现,stu02只能访问父类对象Person的属性,stu01既能访问自己Student的属性也能访问父类Person的属性
* 所以说,将子类对象交给父类对象的引用,这时就需要写上类型。
* 即:当类型和后面new对象类型有继承关系即多态时,就必须写了。
*/
stu01.ID = 10002
stu01.age = 13
stu01.name = "Jack"
stu02.name = "Leo"
stu02.age = 12
}
}
class Person {
var name: String = _
var age: Int = _
}
class Student extends Person {
var ID: Int = _
}
基本语法
对象名.属性名;
示例代码:
package com.lj.scala.obj
/**
* @author Administrator
* @create 2020-03-10
*/
object ObjTest03 {
def main(args: Array[String]): Unit = {
val p1 = new People
p1.name = "Jack"
p1.age = 23
val p2 = p1
println("p1与p2是否相等:" + (p1 == p2)) // true
printf("p1的信息:name=%s, age=%s.\n", p1.name, p1.age)
p1.name = "Tom"
printf("p1的信息:name=%s, age=%s.\n", p1.name, p1.age)
printf("p2的信息:name=%s, age=%s.\n", p2.name, p2.age)
}
}
class People {
var name: String = _
var age: Int = _
}
========================运行结果=============================
p1与p2是否相等:true
p1的信息:name=Jack, age=23.
p1的信息:name=Tom, age=23.
p2的信息:name=Tom, age=23.
========================运行结果=============================
基本说明
Scala中的方法其实就是函数,声明规则请参考函数式编程中的函数声明。
基本语法
def 方法名(参数列表) [:返回值类型] = {
方法体
}
方法的示例代码:
package com.lj.scala.obj
/**
* @author Administrator
* @create 2020-03-10
*/
object ObjTest04 {
def main(args: Array[String]): Unit = {
val dog = new Dog
dog.name = "哮天犬"
dog.color = "白色"
dog.sex = "公"
// 调用Dog对象中的方法dogInfo()
dog.dogInfo()
}
}
class Dog {
var name: String = ""
var color = ""
var sex: String = _
def dogInfo(): Unit = {
println(s"Dog Info: name=$name, color=$color, sex=$sex")
}
}
========================运行结果=============================
Dog Info: name=哮天犬, color=白色, sex=公
========================运行结果=============================
说明
看一个需求:
前面在创建People的对象时,是先把一个对象创建好后,再给他的年龄和姓名属性赋值,如果现在
我要求,在创建人类的对象时,就直接指定这个对象的年龄和姓名,该怎么做? 这时就可以使用"构造方
法/构造器"。
基本介绍
构造器(constructor)又叫构造方法,是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。
回顾-Java构造器基本语法
[修饰符] 方法名(参数列表){
构造方法体
}
回顾-Java构造器的特点
1. 在Java中一个类可以定义多个不同的构造方法,构造方法重载;
2. 如果程序员没有定义构造方法,系统会自动给类生成一个默认无参构造方法(也叫默认构造器),
比如People(){};
3. 一旦定义了自己的构造方法(构造器),默认的构造方法就覆盖了,就不能再使用默认的无参构
造方法,除非显示的定义一下(即: People(){});
回顾-Java构造器的示例代码:
package com.lj.scala.obj;
/**
* @author Administrator
* @create 2020-03-10
*/
public class ObjTest05 {
public static void main(String[] args) {
People p1 = new People("Jack", 12);
String info = p1.getInfo();
System.out.println("info:" + info);
}
}
class People {
String name;
int age;
public People() {}
public People(String name, int age) {
this.name = name;
this.age = age;
}
public String getInfo() {
return name + " -- " + age;
}
}
========================运行结果=============================
info:Jack -- 12
========================运行结果=============================
1. 和Java一样,Scala构造对象也需要调用构造方法,并且可以有任意多个构造方法(即scala中构造器
也支持重载);
2. Scala类的构造器包括: 主构造器和辅助构造器;
3. Scala构造器的基本语法如下:
class 类名(形参列表) { // 主构造器
// 类体
//1. 辅助构造器 函数的名称this, 可以有多个,编译器通过不同参数来区分.
def this(形参列表) { // 辅助构造器
}
def this(形参列表) { //辅助构造器可以有多个...
}
}
示例代码:
package com.lj.scala.obj
/**
* @author Administrator
* @create 2020-03-10
*/
object ObjTest06 {
def main(args: Array[String]): Unit = {
val p1 = new People("Leo", 13)
println("p1 info:" + p1.toString)
val p2 = new People("Tom")
println("p2 info:" + p2.toString)
}
}
/**
* 创建Person对象的同时初始化对象的age属性值和name属性值
*/
class People(inPutName: String, inPutAge: Int) {
var name: String = inPutName
var age: Int = inPutAge
age += 10
println("~~~~~~~~~~~~~~~~~~~~~~~~~~")
// 重写toString,便于输出对象信息。
override def toString: String = {
"name=" + this.name + " <--> age=" + this.age
}
println("ok~~~~~~")
println("age=" + age)
def this(name: String) {
// 辅助构造器,必须在第一行显示调用主构造器(可以是直接,也可以是间接)
this("Leo", 11)
this.name = name // 重新赋值
}
}
========================运行结果=============================
~~~~~~~~~~~~~~~~~~~~~~~~~~
ok~~~~~~
age=23
p1 info:name=Leo <--> age=23
~~~~~~~~~~~~~~~~~~~~~~~~~~
ok~~~~~~
age=21
p2 info:name=Tom <--> age=21
========================运行结果=============================
1. Scala构造器作用是完成对新对象的初始化,构造器没有返回值;
2. 主构造器的声明直接放置于类名之后;
3. 主构造器会执行类定义中的所有语句,这里可以体会到Scala的函数式编程和面向对象编程融合
在一起,即:构造器也是方法(函数),传递参数和使用方法和前面的函数部分内容没有区别;
4. 如果主构造器无参数,小括号可省略,构建对象时调用的构造方法的小括号也可以省略;
5. 辅助构造器名称为this(这个和Java是不一样的),多个辅助构造器通过不同参数列表进行区分,
在底层就是方法构造器重载;
6. 如果想让主构造器变成私有的,可以在()之前加上private,这样用户只能通过辅助构造器来构造对象了;
7. 辅助构造器的声明不能和主构造器的声明一致,会发生错误(即构造器名重复)
辅助构造器示例代码:
package com.lj.scala.obj
/**
* @author Administrator
* @create 2020-03-10
*/
object ObjTest07 {
def main(args: Array[String]): Unit = {
val a1 = new Animal("二哈", 2)
println("动物:name=" + a1.name + " <--> age=" + a1.age)
}
}
class Animal() {
var name: String = _
var age: Int = _
var color: String = _
def this(name: String, age: Int) {
/**
* 辅助构造器无论是直接或间接,最终都一定要调用主构造器,执行主构造器的逻辑,而且需要放在辅助构造器的第一行
* [这点和java一样,java中一个构造器要调用同类的其它构造器,也需要放在第一行]
*/
this()
this.name = name
this.age = age
}
def this(name:String) {
this() // 直接调用主构造器
this.name = name
}
def this(name:String, color: String) {
this() // 直接调用主构造器
this.age = age
}
}
========================运行结果=============================
动物:name=二哈 <--> age=2
========================运行结果=============================
让主构造器变成私有示例代码:
package com.lj.scala.obj
/**
* @author Administrator
* @create 2020-03-10
*/
object ObjTest08 {
def main(args: Array[String]): Unit = {
val a2 = new Animal
}
}
// 在()之前加上private,让主构造器变成私有
class Animal02 private() {
var name: String = _
var age: Int = _
var color: String = _
def this(name: String, age: Int) {
// 说明,由于主构造器变成私有,再通过主构造器调用就会报错
this() // error: ambiguous reference to overloader definition
this.name = name
this.age = age
}
def this() {
this()
}
}
1. Scala类的主构造器的形参未用任何修饰符修饰,那么这个参数是局部变量;
2. 如果参数使用val关键字声明,那么Scala会将参数作为类的私有的只读属性使用;
3. 如果参数使用var关键字声明,那么Scala会将参数作为类的成员属性使用,并会提供属性对应
的xxx()[类似getter]和xxx_$eq()[类似setter]方法,即这时的成员属性是私有的,但是可读写。
示例代码:
package com.lj.scala.obj
/**
* @author Administrator
* @create 2020-03-10
*/
object ObjTest09 {
def main(args: Array[String]): Unit = {
val w1 = new Worker("Jack")
w1.name // 不能访问inPutName
val w2 = new Worker2("Jack")
w2.name
w2.inPutName // 可以访问inPutName
// w2.inPutName = "Tom" // 不可以修改inPutName的值
val w3 = new Worker3("Jack")
w3.name
w3.inPutName // 可以访问inPutName
w3.inPutName = "Tom" // 可以修改inPutName的值
}
}
// 此时的主构造器里的变量inPutName就是一个局部变量
class Worker(inPutName: String) {
var name = inPutName
}
// 此时主构造器里的变量inPutName就是一个private的只读属性
class Worker2(val inPutName: String) {
var name = inPutName
}
// 此时主构造器里的变量inPutName就是一个private的可以读写属性
class Worker3(var inPutName: String) {
var name = inPutName
}
JavaBeans规范定义了Java的属性是像getXxx()和setXxx()的方法。许多Java工具(框架)都
依赖这个命名习惯。为了Java的互操作性。将Scala字段加@BeanProperty时,这样会自动生成规范的
setXxx/getXxx 方法。这时可以使用 对象.setXxx()和对象.getXxx()来调用属性。
注意:
给某个属性加入@BeanPropetry注解后,会生成getXXX和setXXX的方法并且对原来底层自动生成类
似xxx(),xxx_$eq()方法,没有冲突,二者可以共存。
示例代码:
package com.lj.scala.obj
import scala.beans.BeanProperty
/**
* @author Administrator
* @create 2020-03-10
*/
object ObjTest10 {
def main(args: Array[String]): Unit = {
// 测试加了“@BeanProperty”注解的getter与setter方法
val c1= new Company
c1.setName("华为")
println("name:" + c1.getName)
// 测试自带的getter[对象.xxx()]与setter[对象.xxx_$eq()]方法
val c2 = new Company
c2.name_$eq("阿里巴巴")
println("name:" + c2.name)
}
}
class Company() {
@BeanProperty var name: String = _
}
========================运行结果=============================
name:华为
name:阿里巴巴
========================运行结果=============================
看一个案例
package com.lj.scala.obj
import scala.beans.BeanProperty
/**
* @author Administrator
* @create 2020-03-10
*/
object ObjTest10 {
def main(args: Array[String]): Unit = {
val p = new Person("Leo", 20)
}
}
class Person() {
var age: Int = 13
var name: String = _
def this(name: String, age: Int) {
this()
this.name = name
this.age = age
}
}
上面的流程分析
1. 加载类的信息(属性信息,方法信息);
2. 在内存中(堆)开辟空间;
3. 使用父类的构造器(主和辅助)进行初始;
4. 使用主构造器对属性进行初始化 【age:13, name:""】;
5. 使用辅助构造器对属性进行初始化 【 age:20, naem:Jack 】;
6. 将开辟的对象的地址赋给p这个引用。
对以前的知识回顾,加深基础知识!
学习来自:北京尚硅谷韩顺平老师—尚硅谷大数据技术之Scala
每天进步一点点,也许某一天你也会变得那么渺小!!!