不使用str.toLong,str.toInt/Integer.valueOf()/Long.valueOf/Integer.parseInt()等,将字符串"123456789" 转化成数字123456789
def method3(): Unit = {
val str = "123456789"
var sum = 0L
for(ch <- str) {//字符串本身就是一个字符数组
sum = sum * 10 + (ch - '0')
}
println(sum)
str.toCharArray.map(ch => ch - '0').reduce((v1, v2) => v1 * 10 + v2)
}
def main(args: Array[String]): Unit = {
val array = Array(1, 5, 3, 5, 6, 7, 2, 9)
println("排序前的数组:" + array.mkString("[", ", ", "]"))
selectSort(array)
println("排序后的数组:" + array.mkString("[", ", ", "]"))
}
/**选择排序
*
*/
def selectSort(arr:Array[Int]): Unit = {
for(i <- 0 until arr.length) {
for (j <- i until arr.length) {
if(arr(i) > arr(j)) {
swap(arr, i, j)
}
}
}
}
/*
位运算 ^ 相同为0,反之为1
a=3 b=5
a=0011
b=0101
a= a^b =0110
0101
b= a^b =0011=3
0110
a= a^b= 0101=5
这里没有使用第三方变量完成两个数字的交换,其中使用^效率最高
*/
def swap(arr:Array[Int], i:Int, j:Int): Unit = {
/*arr(i) = arr(i) ^ arr(j)
arr(j) = arr(i) ^ arr(j)
arr(i) = arr(i) ^ arr(j)*/
arr(i) = arr(i) + arr(j)
arr(j) = arr(i) - arr(j)
arr(i) = arr(i) - arr(j)
}
// 在一个有序数组中找到某一个值,如果存在,返回索引,没有返回-1或者返回如果存在,应该在的位置
def binarySearch(arr:Array[Int], key:Int):Int = {
var start = 0
var end = arr.length - 1
while(start < end) {
val mid = (start + end) / 2
if (key < arr(mid)) {
//左边
end = mid - 1
} else if (key > arr(mid)) {
//又变
start = mid + 1
} else {
return mid
}
}
return -(start + 1)
}
* 定义scala中的类使用关键字class
* 1、定义scala中的任意一种结构,都不可以使用public关键字修饰,因为scala中没有public关键字
* 不加任何访问权限修饰符就相当于java中的public
* 2、类中可以定义成员信息
* 成员变量
* 成员方法
* 3、创建类的实例--对象
* 在scala中和java中是一样,都使用关键字new来构建类的实例
object ClassOps {
def main(args: Array[String]): Unit = {
val p:Person = new Person()
p.name = "郭靖"
p.age = 18
p.show()
}
}
class Person {
var name:String = _
var age:Int = _
def show(): Unit = {
println(s"name: ${name}\tage: ${age}")
}
}
* 4、scala没法直接为成员变量提供getter和setter方法,只能自己编写
* scala做了一种尝试,通过注解(@BeanProperty)的方式来给成员变量提供getter和setter,
* 前提是该getter或者setter不能被private修饰,此时数据的安全性无法得到保证
*
* 5、这个getter和setter的使用其实javabean中的规范,javabean的主要作用是什么?
* 封装、传递数据
object ClassOps {
def main(args: Array[String]): Unit = {
val p:Person = new Person()
// p.name = "郭靖"
// p.age = 18
p.setName("黄蓉")
p.setAge(-2)
p.setSalary(123.0f)
p.show()
}
}
class Person {
private var name:String = _
private var age:Int = _
@BeanProperty var salary:Float = _
def setName(n:String) = {
name = n //单行函数
}
def getName = name
def setAge(a:Int) = {
if(a < 0) {
throw new RuntimeException(" 赋值错误!")
}
age = a
}
def getAge = age
def show(): Unit = {
println(s"name: ${name}\tage: ${age}")
}
}
/*
在scala中一般不用这些普通的class类进行封装数据、传递数据,那用什么呢?
* case class样例类
* 作用就相当于java bean
* case class的定义非常简单,在class关键字的前面加上另外一个关键字case即可
*
* 样例类的定义必须要有一个参数列表---->构造器,
* case class的应用是非常广泛的,但凡数据的传递,一般都用case class
*/
object _02CaseClassOps {
def main(args: Array[String]): Unit = {
val category = Category(1, "手机")
println(category.id)
println(category.name)
}
}
//定义了一个case class Category
case class Category(id:Int, name:String)
* 2、构造器:
* 按照java中的知识,val stu = new Student是使用Student类的无参构造器创建对象
* 在一个类中,如果局部变量和成员变量名发生冲突,便通过给成员变量加this关键字进行区分
* 3、如何定义构造器:
* 尝试使用def Student(name:String, age:Int)定义构造器,
* 调用的时候:
* new Student("郭靖", 20) too many arguments to constructor报错
* 所以该方法就不是scala中的构造器
* 4、scala的构造,分为主构造器和辅助构造器,
* 主构造器的定义和类的定义交织在一起,如何去定义一个主构造器
* class Xxx(参数列表) {
* }
* 类名后面的内容就是主构造器,如果参数列表为空的话,()可以省略
* 主构造器的函数体,就是类体的内容,所以如果我们使用主构造器创建对象
* 5、scala的类有且仅有一个主构造器,要想提供更加丰富的构造器,就需要使用辅助构造器
* def this(参数列表)
* scala中的辅助构造器,在函数体的第一行,必须以调用其它辅助构造器或者主构造器开始
* 也就是说要使用this(参数列表)去调用其它构造器
* 但是归根到底,一个辅助构造器最终还是要从主构造器的调用开始
* 6、scala和java的构造器的区别
* java的构造器没有主构造器和辅助构造器之分,但是有默认的无参构造器和有参构造器之分
* scala中默认的构造器就是类名后面的构造器,被称之为主构造器,同时还拥有辅助构造器
* java的构造器名称和类名一直,而scala中的构造器名称就是this,其余和java一模一样
class Student(n:String, a:Int) {
private var name:String = _
private var age:Int = _
def Student(name:String, age:Int): Unit = {
this.name = name
this.age = age
}
//辅助构造器
def this() {
this("黄蓉", 18)
println("---辅助构造器def this()-----")
}
def this(age:Int) {
this()
this.age = age
println("---辅助构造器def this(age:Int)-----")
}
def show(): Unit = {
println(s"name: ${n}\tage: ${a}")
}
println("如果这是构造器的方法体的话,这句话应该会被调用!")
}
scala中称之为嵌套类,在java中称之为内部类
java中的成员内部类实例
public class InnerClassOps {
public static void main(String[] args) {
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
class Outer {
class Inner {
public void show() {
System.out.println("inner show");
}
}
}
为啥要有内部类?
从业务逻辑上理解,定义复杂是否在外部类内部定义更加合理,这样便有了内部类,比如,定义一个类Person,类有心脏,Heart优势一个复杂的抽象事物,显然应该把Heart定义在Person内部更加的准确与合理。
scala的内部类如何定义
object _03InnerOps {
def main(args: Array[String]): Unit = {
val outer = new Outer
val inner = new outer.Inner()
inner.show()
}
}
class Outer { oo => //外部类的引用
var x = 5
class Inner {
var x = 6
def show(): Unit = {
var x = 7
println("Inner: x=" + x)//7
println("Inner: x=" + this.x)//6
println("Inner: x=" + Outer.this.x)//5
println("Inner: x=" + oo.x)//5 简写方式
}
}
}
scala并没有像java中的静态,所以按照java中的观点的话,主函数是没有办法被执行public static void main(xxx)
scala为了来模拟java中的static这个关键字,设计出了object这一结构,它是和class平级。
在object定义的方法我们可以理解为函数,class中的行为称之为方法,而且在object中定义的变量和函数都是可以当做java中的静态来进行调用。
object _04ObjectOps {
def main(args: Array[String]): Unit = {
val ret = Tool.add(13, 14)//相当于java的静态方法
}
}
object Tool {
val x = 5
def add(a:Int, b:Int) = a + b
}
如何在scala中去定义单例对象呢?
java中的单例
/**
* 单例
* 饿汉式
* 懒汉式
* 一个类只能创建一个对象,
* 定义的步骤:
* 恶汉式:
* 1、私有构造器
* 2、提供一个public的static的返回值为本类引用的方法
* 3、为了给第2步中提供实例,创建一个private的static的成员变量
* 懒汉式:
* 1、私有构造器
* 2、创建一个private的static的成员变量,没有初始化
* 3、提供一个public的static的返回值为本类引用的方法
*/
饿汉式:
class Singleton {//饿汉式
private Singleton(){}
//成员位置
{//构造代码块
}
private static Singleton instance = new Singleton();
// static {
// instance = new Singleton();
// }
public static Singleton getInstance() {
return instance;
}
}
懒汉式:
class Singleton {
private Singleton(){}
private static Singleton instance;
public static Singleton getInstance() {
if(instance == null) {
synchronized (Singleton.class) {
if(instance == null)
instance = new Singleton();
}
}
return instance;
}
}
scala中的单例
object _05SingletonOps {
def main(args: Array[String]): Unit = {
val s1 = Singleton
val s2 = Singleton
println("s2.x=" + s2.x)//1
s1.x = 5
println("s1 == s2? " + (s1 == s2))//true 单例
println("s2.x=" + s2.x)//5
}
}
object Singleton {
var x = 1
}
为什么要有伴生对象?
我们都知道,在scala中是没有静态这个概念,而在java中一个类是既可以有非静态的成员,也可以有静态成员,表达非常丰富。scala由于没有静态的概念,类只能拥有非静态成员。所以scala为了弥补这个缺憾,定义这么一个和该类同名的object结构,而且该object结构必须要和该类在同一个.scala源文件中被定义。
这样我们就可以让该类拥有了静态和非静态的成员。
把这个和类同名的object称之为该类的伴生对象,反过来,该类称之为该object的伴生类。
object _06CompanionOps {
def main(args: Array[String]): Unit = {
val worker = new Worker("乔峰", 38)
worker.show()
println("-----------------------------")
val w1 = Worker()
w1.show()
println("静态属性:" + Worker.x)
val w2 = Worker("段誉", 20)
w2.show()
// val arr = new Array[Int](5)
// val arr1 = Array(1, 2, 3, 4)
}
}
class Worker /*private ()*/ {
private var name:String = _
private var age:Int = _
def this(name:String, age:Int) {
this()
this.name = name
this.age = age
}
def show(): Unit = {
println(s"name:${name}, age:${age}")
}
}
object Worker {
var x = 123
//apply方法必须要重写
def apply(): Worker = new Worker()
def apply(name: String, age: Int): Worker = new Worker(name, age)
}
object _07AppOps extends App {
/*def main(args: Array[String]): Unit = {
println("xxxxxx")
}*/
println(args.mkString("[", ",", "]"))
println("yyyyyyyyyyyy")
}
extends:扩展
trait:特质
* scala的继承或者扩展
* 如何去实现继承或者扩展,在scala中使用的关键字和java的继承是一模一样extends
* 总结:
* 1、子类可以拥有父类的非私有的成员(成员变量和成员方法)
* 2、子类可以扩展|复写父类的方法,但是在复写的时候,必须要添加override关键字(除非该方法是抽象方法)
* 3、哪些成员无法被子类继承
* private
* 如果private关键字不加如何限制,就和java中的private作用是相同的,但是我们在scala中可以更加精准
* 的控制被private或者被protected关键字修饰的成员的权限。
* private[可以被访问的包package]
* 这就意味着,该成员可以在包package,及其子包下面被访问
* private[this] <=> private
* 只能在前类中被访问
* static scala中没有
* final
* 4、子类要想使用父类的某些行为,可以使用super关键字来调用,和java中一致
class Dog {
private[extendz] var id:String = "哺乳类的人类的好朋友"
var eyes:Int = 2
var name:String = _
def eat(): Unit = {
println("吃吃吃")
}
private def cry(): Unit = {
println("汪汪汪汪")
}
}
class ZHTYQ extends Dog {
name = "大黄"
override def eat(): Unit = {
super.eat()
println("大黄啃骨头。。。")
}
id = "haha"
def keepDoor(): Unit = {
println("大黄在看家")
}
}
多态:一种事物有多重状态的表现,是继承体系中非常重要的概念。
反映到编程语言中的体现:父类引用指向子类对象。这个在java中是很明显的,但是在scala不明显,因为一般在定义变量的时候,可以不添加类型,直接做类型推断,所以要想很直接的体现出,就应该像java定义那样,eg.
val obj:Fu = new Zi() —> 父类引用指向子类对象 val obj = new Zi()
同时在进行多态操作中,一般都会涉及到类型转化,scala中也有类似java中的类型检查和类型转化,不同之处在于具体操作方式略有差异,进行类型检查是:引用.isInstanceof[类型],进行类型转化使用引用.asInstanceof[类型]。
class Person {
var name:String = _
var age:Int = _
def this(name:String, age:Int) {
this()
this.name = name
this.age = age
}
override def equals(obj: scala.Any): Boolean = {
if(!obj.isInstanceOf[Person]) {
return false
}
val that = obj.asInstanceOf[Person]
if(this.name.equals(that.name) && this.age == that.age) {
return true
}
return false
}
}
但是,考虑到scala是一个非常简约的编程语言,又为大家提供了一个类型检查和转化的简化的操作方式——模式匹配,和java中switch case很像,但是要比java中的switch case强大的多的多的多。
private def method3 = {
val dh: Dog = new ZHTYQ
dh.eat()
if (dh.isInstanceOf[ZHTYQ]) {
//会避免出现ClassCastException
val gg = dh.asInstanceOf[ZHTYQ]
gg.keepDoor()
}
println("-----------------------")
//使用模式匹配的操作方式 和switch case很像
dh match {
case gg:ZHTYQ => {
gg.keepDoor()
}
case p:Person => {
p.name
}
//还有默认的操作
case _ => {
println("没有匹配到任何")
}
}
}
所谓受保护的字段或者方法,就是被protected修饰的field或者method。
被protected有啥特点?本类及其子类方法。
> **被protected[this]修饰了成员,便无法在实例(包括本类对象和子类对象)中被调用,只能在定义中被调用**
举例:
/** * 因为salary被protected[this]修饰了,便无法在实例中被调用,只能在定义中被调用 */ class Staff { var name:String = _ var age:Int = _ protected[this] var salary:Float = 2120 def doWork(): Unit = { println(this.name + " is working sth.") } } class Programmer extends Staff { name = "郭靖" age = 52 salary = 1000000000 override def doWork(): Unit = { println(this.name + " 监督杨过练武") } def makeFields(staff: Staff): Unit = { println(this.name + "准备要和" + staff.name + "建立革命友谊") println(staff.name + "的薪资是多少呢?" + staff.salary) } }
/**
* 子父类的构造
* 子类在构造的过程中,先要初始化相关的父类构造器
*/
object _04ExtendsOps {
def main(args: Array[String]): Unit = {
val zi = new Zi
zi.name = "郭靖"
zi.age = 22
zi.show()
}
}
class Fu {
println("-----Fu---main-constructor---")
var name:String = _
var age:Int = _
def this(name:String, age:Int) {
this()
this.name = name
this.age = age
println("-----Fu---assist-constructor(name:String, age:Int)---")
}
}
class Zi(gender:Int) extends Fu {
println("-----Zi---main-constructor(gender:Int)---")
def this() {
this(1)
println("-----Zi---assist-constructor()---")
}
def show(): Unit = {
println(s"name:${name}, age: $age, gender:$gender")
}
}
执行过程:
-----Fu---main-constructor---
-----Zi---main-constructor(gender:Int)---
-----Zi---assist-constructor()---
name:郭靖, age: 22, gender:1
子类调用父类有参构造
class Fu {
println("-----Fu---main-constructor---")
var name:String = _
var age:Int = _
def this(name:String, age:Int) {
this()
this.name = name
this.age = age
println("-----Fu---assist-constructor(name:String, age:Int)---")
}
}
class Zi(name:String, age:Int, gender:Int) extends Fu(name, age) {
println("-----Zi---main-constructor(gender:Int)---")
def this() {//辅助构造器
this("zhangsan", 14, 1)
println("-----Zi---assist-constructor()---")
}
def show(): Unit = {
println(s"name:${name}, age: $age, gender:$gender")
}
}
执行过程:
-----Fu---main-constructor---
-----Fu---assist-constructor(name:String, age:Int)---
-----Zi---main-constructor(gender:Int)---
-----Zi---assist-constructor()---
name:zhangsan, age: 14, gender:1
总结:
scala在加载子类构造器的同时去加载父类构造器,其道理和java中是一致的,不同点在于,scala只有主构造器才
可以直接调用父类的构造器(主构造器和辅助构造器),辅助构造器是无法直接调用父类的构造器,因为在辅助构造
器的第一句话必须是this,去调用其他辅助构造器或者主构造器,所以辅助构造器只能通过主构造器来间接的调用父
类的构造器。
其实说白了就是匿名内部类,啥叫匿名类?匿名子类?
没有名字的类就叫匿名类,没有名字的类就叫做匿名子类。
什么又叫做有名字的类。
public class Person{}—>这就是有名字的,定义好有名字的类。源码阶段的概念
new Person() {} —>这就是一个没有名字的类 —>运行时的概念
匿名子类最常见的作用,一般都在某个操作仅仅出现一次的时候被使用,在方法的参数上面多出现匿名子类,
在java中出现最多的匿名类或者匿名子类,就是接口或者抽象类。
java中匿名类的使用
public class DynamicProxyOps {
public static void main(String[] args) {
/*
构建一个Singer动态代理的对象
类加载器
源代码 .java --->编译-->.class --类加载器-> jvm
*/
final Singer singer = new Singer("郭靖", 22);
Singers proxySinger = (Singers) Proxy.newProxyInstance(
singer.getClass().getClassLoader(),
singer.getClass().getInterfaces(),
new InvocationHandler() {
//代理的方式
/**
*
* @param proxy 这个就是代理之后的对象
* @param method 要代理的对象上面的方法
* @param args 当前method对应的参数
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("出任丐帮帮主");//前置通知
Object result = method.invoke(singer, args);
System.out.println("打狗棒法传授一下");//后置通知
return result;
}
}
);
proxySinger.sing();
}
}
interface Singers {
void sing();
}
class Singer implements Singers {
private String name;
private int age;
public Singer(String name, int age) {
this.name = name;
this.age = age;
}
public void sing() {
System.out.println(name + " 正在练武");
}
}
scala中使用匿名类
object _05ExtendsOps {
def main(args: Array[String]): Unit = {
val worker = new Worker("郭靖", 22)
val 警察叔叔 = new Worker("阿 sir.", 28){//匿名子类
override def work(): Unit = {
super.work()
println("为莘莘学子保驾护航~~~")
println("阿 sir。辛苦了")
}
def fetchThief(): Unit = {
println("阿 sir专抓偷心贼")
}
}
警察叔叔.fetchThief()
worker.makeFriend(警察叔叔)
}
}
class Worker {
var name:String = _
var age:Int = _
def this(name:String, age:Int) {
this()
this.name = name
this.age = age
}
def makeFriend(worker: Worker): Unit = {
println(this.name + "和 " + worker.name + "成为了工友")
worker.work()
}
def work(): Unit = {
println("劳心者治人,劳力者治于人")
}
}
what is abstract?
编程语言中的抽象,就是只给出了定义,并没有给出实现。只能交由具体的实现者来完成,为了表示抽象和非抽象(具像,具体),在java或者scala中使用关键字abstract来进行标识。
> 需要指出的是,在java中只有抽象方法,没有抽象字段,但是在scala既有抽象方法,又有抽象字段。
特点
object _06AbstractOps {
def main(args: Array[String]): Unit = {
val p = new Chinese
p.eat()
}
}
abstract class Human {
var name:String
var birthday:String = _
def eat()
def sleep(): Unit = {
println("中午不睡,下午崩溃~")
}
}
class Chinese extends Human {
def eat(): Unit = {
println(name + "使用筷子吃饭")
}
override var name = "炎黄子孙"
}
有一个疑问?
大伙在java学习过,只能单继承,无法多继承,原因是什么?
如果一个类,继承两个类,而这两个类都有相同的方法,子类在使用过程中无法辨别该方法到底来源于哪一个父类。
java中为了解决这个只能单继承的问题,提出了两个方案,第一个就是多层继承,这是从纵向解决;第二个就是多实现。
scala也只能进行单继承和多层继承,无法多继承。
trait特质是一个和class、object同一level的结构。
trait和java中的接口有点像,但不完全一样,java中的interface中的所有的方法都是抽象的,而trait既可以拥有抽象方法,也可以拥有非抽象方法,所以其实可以理解为抽象类。
已经有了一个抽象类,那干嘛有搞出一个trait特质呢?
那是因为,如果只有抽象类的话,在继承体系中只能单继承和多层继承,无法多extends,所以需要一个新的结构来弥补,这个结构就是trait特质。
需要大家注意的是,java中实现一个interface使用关键字implement,实现多个interface时候,interface之间使用“,”分割,scala中扩展trait的时候,同样也是用extends关键字,扩展多个trait的时候,trait之间使用with关键字连接。
如果trait中的所有的方法都是抽象的,那就是java中的interface。
示例:
object _07TraitOps {
def main(args: Array[String]): Unit = {
val mp = new MainOperation
mp.debug("取法乎上仅得乎中,取法乎中仅得其下,取法乎下仅得其下下")
}
}
//特质
trait Logger {
def log(msg:String)
}
trait ConsoleLogger extends Logger {
override def log(msg: String): Unit = {
println("ConsoleLogger> " + msg)
}
}
class FileLogger extends Logger {
override def log(msg: String): Unit = {
println("FileLogger> " + msg)
}
}
class DailyFileLogger extends Logger {
override def log(msg: String): Unit = {
println("DailyFileLogger> " + msg)
}
}
class MainOperation extends ConsoleLogger with Logger{
def debug(msg:String): Unit = {
print("debug: ")
super.log(msg)
}
}
混入:
把上述的MainOperation修改一下:
class MainOperation extends ConsoleLogger {
def debug(msg:String): Unit = {
print("debug: ")
super.log(msg)
}
}
如果这是张三开发的代码,李四在用的时候,觉得之extends ConsoleLogger不完善,还需要扩展其他的trait,但是联合开发的话,一般都不要随便修改别人的代码。
但是还是想要增加新的功能,怎么做呢,一种方式新写一个类集成张三写的类的同时又扩展新的的功能,可以,但是略微麻烦一点,所以这里在scala中使用混入这样一个概念去处理。
在运行时去扩展一个特质,如下,便让李四写的对象在原有的基础之上增加新的功能,对原先的类没有侵入。
val mmp = new MainOperation with MyTrait //scala特质的混入 mix in
mmp.debug("dafaff")
mmp.show()
trait MyTrait {
def show(): Unit = {
println("江上如此多娇~")
}
}