热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Scala尾递归泛型类型上下限界定多重界定视图界定型变(协变逆变)隐式转换SAM...

0.尾递归可以进行优化,将递归转换成循环实现,避免栈的溢出。defsum(args:Seq[Int]):BigInt{if(args.isEmpty)

0.尾递归

可以进行优化,将递归转换成循环实现,避免栈的溢出。
def sum(args:Seq[Int]):BigInt = {if(args.isEmpty) 0 else args.head + sum(args.tail)
}
sum(1 to 10000) //溢出//实现了尾递归//实现尾递归sum2函数接受两个函数x:Seq[Int]:序列 part:BigInt:累加求和每次产生的部分值
def sum2(x:Seq[Int] , part :BigInt):BigInt = {if(x.isEmpty) part else sum2( x.tail ,x.head + part)
}
sum2(1 to 100000 , 0) //okdef out(str:String):Unit= {out(str)println(str)
}
/**
在Scala中它可以将尾递归转换成循环。就不会出现栈溢出了。
* 尾递归:它把这个递归函数,若最后一条语句是递归本身。它可以把这种递归转成循环。就可以避免栈溢出。StackOverflowError(栈溢出异常)
*/
object TailRecursiveDemo{//用递归计算累加和,递归函数必须要定义返回值类型
def sum(list:List[Int]):Int={if(list.isEmpty)0 else list.head +sum(list.tail)//这里加了判断,它最后的语句就不是递归是0,所以不是尾递归
}//这个函数不是尾递归,为什么?因为它最后一条语句不是递归def main(args: Array[String]):Unit={val list=List(1 to 100:_*)println(sum(list))}
}

1.泛型

//定义泛型类
class Pair[T,S](val first:T,val second:S)
泛型的使用
object GenericTypeDemo{def main(args:Array[String]):Unit={//Pair[T,S]这个决定后面的属性:(var first:T,var second:S)是什么类型class Pair[T,S](var first:T,var second:S)//val p1=new Pair[Int,String](1,"tomas")//类型推断val p2=new Pair(1,"tomas")--------------------------------//方法定义泛型def middle[T](arr:Array[T]):T={arr(arr.length/2)}//调用函数var arr=Array(1,2,3,4)println(middle(arr)) //3//asInstanceOf这个也是泛型val obj=""obj.asInstanceOf[String]}
}
[Java里面的泛型]
public static T getMiddle(Listlist){return list.get(list.size()/2);
}
//调用java里面的泛型
【Maven】
junitjunit4.11

@Test
public void testMethod(){Listlist=new ArrayList();list.add(1);list.add(2);list.add(3);list.add(4);System.out.println(getMiddle(list)); //2
}
//在方法调用中指定类型,通过对象来调用
public static T getMiddle(Listlist){return list.get(list.size()/2);
}
@Test
public void testMethod(){Listlist=new ArrayList();list.add(1);list.add(2);list.add(3);list.add(4);//在方法调用中指定System.out.println(getMiddle(list));
}

2.类型变量的界定

类型变量界定:指的就是范围(上限和下限)
现在你想要添加一个方法,产生较小的那个值:产生较小值的话。它要能够比较大小
class Pair[T](val first:T,va; second:T){//在上面直接定义了一个T作为一个泛型&#xff0c;在方法体中first.compareTo(second)<0)小于他&#xff0c;小于0就返回。就是T或者first是否有没有这个方法&#xff1f;它不一定有。所以它可能是错的。为了保证它一定有可以添加添加一个上界T<:Comparable[T]> 上限&#xff0c;就是要小于T<:Comparable[T]> def smaller&#61;if(first.compareTo(second)<0)first else second //错误
}
这是错的----我们并不知道first是否有compareTo方法。要解决这个问题&#xff0c;我们可以添加一个上界T<:Comparable[T]> 上限//定义上界限
//class Pair[T ](var first:T,var second:T){//它没有<:Comparable[T]识别不了
class Pair[T <:Comparable[T]](var first:T,var second:T){//定义一个方法要取&#xff0c;取它两个大的值。T//获取两个属性中较大的一个def max():T&#61;{if&#xff08;first.compareTo(second)>0&#xff09;first else second;}
}
val p1&#61;new Pair(100,200)//报错&#xff0c;它不能比较大小在scala中它并没有Comparable
val p1&#61;new Pair("100","200")//200
//注意了在Java里面和scala里面字符窗String 有什么区别
type String &#61;java.lang,String //scala里面的串就是java里面的串&#xff0c;它就是一个别名
type Class[T]&#61;java.lang.Class[T]
println(p1.max())
Int的是AnyVal&#xff0c;Int的不是别名。它没有Comparable的特点。所以它比较不了。
如果要向实现数字的大小比较&#xff0c;需要用到视图界定
[Int的源码翻看]
final abstract class Int private etends AnyVal{}
//考察下界
class Animal
class Dog extends Animal
class Jing8 extends Dog
//T&#xff0c;没有任何说法&#xff0c;什么都可以
//Pari是有两个属性的&#xff0c;都是T类型.现在添加一个方法将first替换掉&#xff0c;保留第二个不变第一个变掉
class Pair[T](var first &#xff1a;T&#xff0c;var second:T){//R需要是T的超类//def replaceFirst[R >:T](newele:R)&#61;{def replaceFirst[R >:T](newfirst:R)&#61;{//new Pair(newele,second)new Pair(newfirst,second)}
}
val d1&#61;new Dog()
val d2&#61;new Dog()
val p1&#61;new Pair[Dog](d1,d2)
val jing8&#61;new Jing8()
val p2&#61; p1.replaceFirst(jing8)
//加了泛型它就有要求&#xff0c;需要给方法显示指定泛型
val p2&#61; p1.replaceFirst[Jing8](jing8)
//给它一个新的类型
val a1&#61;new Animal()
p1.replaceFirst[Animal](a1)
println(p2)1.类上泛型class Pair[T,S](var first:T , var second:S) val p &#61; new Pair[Int,String](100,"tom")val p &#61; new Pair(100,"tom")2.方法上泛型def mid[T](arr:Array[T]) &#61; arr(arr.length / 2)mid[Int](Array(2,3,4))mid(Array(2,3,4))3.类型上限界定class Pair[T <: Comparable[T]] (var a:T ,var b:T)val p &#61; new Pair("100","100")4.类型下限界定class Pair[T >: Jing8](var fst:T ,var sec:T){// 替换一个新的元素 ele:R代表ele的元素类型是R类型。def replaceFirst[R >: T](ele:R) {//new Pair(ele , sec) ;表示下界&#xff0c;R必须是父类才可以new Pair(ele , sec) ;//把原sec放这替换ele}}val d1 &#61; new Dog()val d2 &#61; new Dog()val p1 &#61; new Pair(d1,d2)//val jing8 &#61; new Jing8()//错误&#xff0c;jing8是dog的子类&#xff0c;不符合下界范围p1.replaceFirst[Jing8](jing8)//替换&#xff0c;必须要把泛型写上[Jing8]val a1 &#61; new Animal()//OK , 符合下界范围p1.replaceFirst[Animal](a1)

3.视图界定

视图界定<% //相当于模糊查询&#xff0c;能够隐式转换成目标类
class Pair[T<% Comparable[T]](var first:T,var second:T){//获取两个属性中较大的一个def max():T&#61;{if(first.compareTo(second)>0)first else second;}
}<% //相当于模糊查询&#xff0c;能够隐式转换成目标类也可以。class Pair[T <% Comparable[T]] (var a:T , var b:T)val p &#61; new Pair(100,200)
上下文界定视图界定T<%V要求必须存在一个从T到V的隐式转换。上下文界定的形式为T&#xff1a;M&#xff0c;其中M是另一个泛型类。它要求必须存在一个类型为M[T]的"隐式值"。class Pair[T:Ordering] //Ordering必须存在隐式值才行

4.多重界定

先大于后小于//R>:Jing8 <:Animal,
类型变量可以同时有上界和下界。写法为&#xff1a;T>:Lower <:Upper
class Animal
class Dog extends Animal
class Cat extends Animal
class JiaFeiCat extends Catclass Jing8 extends Dog
class LocalJing8 extends Jing8class Pair[T](var first:T,var second:T){//现在的要求就是替换的数它得是Animal的子类同时也是LocalJing8的父类def replaceFirst[R <:LocalJing8<:Animal ](ele:R)&#61;{new Pair(ele,second)}
}
val a1&#61;new Animal
val d1&#61;new Dog
val d2&#61;new Dog
val jing81&#61;new Jing8()
val jing82&#61;new Jing8()
val local1&#61;new LocalJing8()
val local2&#61;new LocalJing8()
val c1&#61;new Cat()val p1&#61;new Pair[Dog](d1,d2)
//对它进行替换&#xff0c;它必须是Animal的子类LocalJing8的父类
val pp&#61;p1.replaceFirst[Animal]&#xff08;a1&#xff09; //动物本身可以
val pp&#61;p1.replaceFirst[Cat]&#xff08;C1&#xff09;//do not conform to method replaceFirst&#39;s type parameter bounds 它不符合参数类型的边界
val pp&#61;p1.replaceFirst[LocalJing8]&#xff08;local1&#xff09;//可以进来了&#xff0c;它是包含的
println(pp) //200
//就定义一个Jing8是不可以的def replaceFirst[R <:Jing8<:Animal ](ele:R)&#61;{
def replaceFirst[R <:Jing8<:Animal ](ele:R)&#61;{new Pair(ele,second)}
val p1&#61;new Pair[Dog](d1,d2)
val pp&#61;p1.replaceFirst[LocalJing8](local1)
println(pp)//do not conform to method replaceFirst&#39;s type parameter bounds 它不符合参数类型的边界//R >: Jing8 <: Animal , 先大于后小于。class Pair[T] (var first:T , var second:T) {//能传给方法给replaceFirst的是谁&#xff1f;def replaceFirst[R >: LocalJing8 <: Animal] (ele :R) &#61; {new Pair(ele, second) ;}}

5.型变

class Person
class Student extends Person
class Teacher extends Personclass Pair[T](var first:T,val second:T){def makeFriends(frd:Pair[Person])&#61;{println("hello world")}
}
val p1&#61;new Pair[String]("bob","alice")
val p2&#61;new Pair[Person](new Person,new Person)
如果Student是Person的子类&#xff0c;那么我可以用Pair[Student]作为参数调用makeFriends吗&#xff1f;
缺省情况下&#xff0c;这是个错误。尽管Student是Person的子类型&#xff0c;但Pair[Student]和Pair[Person]之间没有任何关系。现在是让Person和Student之间有继承关系。
p1.makeFriends(p2)1)协变&#xff0c;就是变化方向相同[&#43;T]就是协变按照相同方向改变。class Personclass Student extends Personclass Teacher extends Person//协变&#xff0c;变化方向相同class Pair[&#43;T](val first: T, val second: T) {//Person和Student是有继承关系的和Pair和Person&#xff0c;Student没有继承关系&#xff0c;如果要想有这样的关系就编写在定义Pair类时表明这一点class Pair[&#43;T](val first:T,val second:T)def makeFriends(frd : Pair[Person]) &#61; {println("hello world")}}val p1 &#61; new Pair[Person](new Person , new Person)val p2 &#61; new Pair[Student](new Student , new Student)p1.makeFriends(p2)2)逆变 Student是Person的子类Pair Person类的父类成相反方向变换.Pair[Student]是Pair[Person]的父类。

6.隐式转换

隐式转换函数&#xff08;implicit convcrsion function&#xff09;指的是那种以implicit关键字声明的带有单个的函数。这样的函数将被自动应用&#xff0c;将指从一种类型转换为另一种类型

/**隐式转换测试
*/
object ConvertDemo{def main(args:Array[String]):Uint&#61;{//定义分数类// case class Fraction(val top:Int,val bot:Int){// def mulby(f2:Fraction)&#61;{// Fraction(top*f2.top,bot*f2.bot)// }}//定义隐式函数implicit def int2Frction(n:Int)&#61;{Fraction(n,1)}val f1&#61;Fraction(1,2)val f2&#61;Fraction(2,3)val f3&#61;Fraction(f2)println(f3) //Fraction&#xff08;2&#xff0c;6&#xff09;println(f3.mulby(4)) //Fraction&#xff08;8&#xff0c;6&#xff09;//如果你函数的参数只有一个&#xff0c;那你就可以把这个方法变成操作符放中间。println(f3 mulby 4)//典型的中置 //Fraction&#xff08;8&#xff0c;6&#xff09;}
}
工作原理&#xff1a;都是引进了一些隐式转换函数&#xff0c;当你把不符合条件的参数变成符合条件的对象
[工具类]
//object 是单例对象 里面的方法都是静态的
object MyConverterUtil{implicit def int2Fraction(){}
}[JavaConversions(scala.collection)源码解析]
Object JavaConversions extends WrapAsScala with WrapAsJava
里面定义了很多隐式转换
implicit def as ScalaIterator[A](it:ju.Iterator[A]):Iterator[A]&#61;it match{case IteratorWrapper(wrapped)&#61;>wrappedcase _&#61;>JIteratorWrapper(it)
}
..
//常用的 它的参数是List ju&#61;java.util
//可以这样引用命名空间 import java.{lang &#61;>jl,util&#61;>ju},java.util.{concurrent&#61;>jc}
implicit def asScalaBuffer[A](l:ju.List[A]):mutable.Buffer[A]&#61;l match{case MutableBufferWrapper(wrapped)&#61;>wrappedcase _&#61;>new JListWrapper(l)
}
[RichInt(RichInt(scala.runtime))]//这个类是可以比较大小的。
//RichInt实现了ScalaNumberProxy&#xff0c;它实现了scala数字的代理。它就可以比较大小
final class RichInt(val self:Int)extends AnyVal with ScalaNumberProxy[Int]with RangedProxy[Int]{}
//Comparable有序的
trait Ordered[A]extends Any with java.lang.Comparable[A]{}
//Ordered的类型就是
type Ordered[T]&#61;scala.math.Ordered[T]
val Numeric&#61;scala.math.Ordered
//OrderedProxy这个是代理&#xff0c;Ordered它有接口的实现
trait OrderedProxy[T]extends Any with Ordered[T]with Typed[T]{protected def ord:Ordering[T]def compare(x:T)&#61;ord.compare(self,y)
}Int.scala
implicit scala.language.implicitConversions //implicitConversions隐式转换引入隐式转换导包&#xff1a;
import com.horstmann.impatient.FractionConversions._
在导的时候可以带下划线&#xff0c;也可以导具体的方法。
import MyCoverterUtil //如果不想全部导进来就可以导局部的
import MyCoverterUtil.int2Fraction //导入具体的隐式转换函数。//隐式值测试
object ImplictValueDemo{def main(args:Array[String])&#61;{//修饰函数def decorate(pref&#xff1a;String&#61;"<<<",str:String,suf:String&#61;">>>")&#61;{pref&#43;str&#61;suf}////带名参数println(decorate(str&#61;"hello"))//假如你有很多方法都有implicit这个类型的参数&#xff0c;在绝大多数情况下都以这个值做为参数传递。就可以把这个值定义为默认值。隐式参数是不 可以完成作业的&#xff0c;它一定要跟隐式值配合。def decorate(implicit pref:String,str:String)&#61;{pref&#43;str}//抛异常&#xff1a;//如果在引入隐式转换的时候&#xff0c;有多个的时候&#xff0c;会报异常。此时可以引具体的方法import MyConverterUtil.prefixprintln(decorate(str&#61;"hello"))//implicit val&#43;字符串pref:String就成了隐式值implicit val pref:String&#61;"<<<"println(decorate())}
}典型的
val list&#xff1a;List[Int]&#61;List(1 to 10:_*)
//implicit bf隐式参数就可以找到一个隐式值将它传进来。这也是柯里化(一次只处理一个参数)的好处。隐式参数定在一起没法弄。
//map[B,That](f:(String)&#61;>B)(implicit bf&#xff1a;CanBuildFrom[List[String],B,That])That
list.map(_*2)
1.隐式转换函数 object Utils{implicit def int2Fraction(n:Int) &#61; {Fraction( n, 1)}}import Utils._3 * Fraction(1,2)2.隐式参数//柯里化函数implicit val pref:String &#61; "<<<"def dec(str:String)(implicit pre:String)dec("hello")3.隐式值implicit val xx:String &#61; "<<<"def dec("hello")

7.SAM

SAM&#xff08;函数在java里面就是接口&#xff09;&#xff08;隐式转换函数的应用&#xff09;single abstract method&#xff08;单个抽象方法&#xff09;
object SAMDemo{//每次实现奇数加1var click:Int&#61;0def main(args:Array[String]):Unit&#61;{val frame&#61;new JFrame()frame.setTitle("hello swing")frame.setBounds(50,50,200,100)frame.setVisible(true)//加按钮之前设置一下布局为空frame.setLayout(null);val btn&#61;new JButton()btn.setBounds(0,0,100,50)btn.setText("ok")//实现点击一下加1btn.addActionListener(new ActionListener{//ActionListener public interface ActionListener extends EventListener 它就一个 public void actionPerformed&#xff08;ActionEvent e&#xff09;抽象方法。。典型的匿名类对象override def actionPerformed(e:ActionEvent)&#61;{//常规的Java实现//给按钮一个点击事件&#xff0c;每次点击一下加1 &#xff0c;scala可以做sam抽象&#xff0c;一个抽象方法click&#43;&#61;1println(click) //1,2,3,,4,5,6,,7,....15}})//(e:ActionEvent)&#61;>{click_&#43;&#61;1;println(click)这个传的是一个函数&#xff0c;而不是需要的事件监听器。为了让这种方式成为可能&#xff0c;就要做一个隐式转换。隐式转换就是直接能把(e:ActionEvent)&#61;>{click_&#43;&#61;1;println(click)转换成ActionListener实现就可可以了// btn.addActionListener((e:ActionEvent)&#61;>{click_&#43;&#61;1;println(click)})//从函数到func2ActionLisnter的转换func2ActionLisnter&#xff08;&#xff09;的参数是一个函数&#xff0c;{click_&#43;&#61;1;println(click)函数本身没有返回值。参数是ActionEvent类型//定义隐式转换函数&#xff0c;将函数转换成actionListen对象&#xff08;SAM转换&#xff09;implicit def func2ActionListnter(f:(ActionEvent)&#61;>Unit)&#61;{new ActionListener{override def actionPerformed(e:ActionEevent)&#61;{f(e)}}}btn.addActionListener((e:ActionEvent)&#61;>{click&#43;&#61;1;println(click)});frame.add(btn)//frame.setVisible(true)}
}

转:https://www.cnblogs.com/SteveDZC/p/9771241.html



推荐阅读
  • 本文介绍了如何利用ObjectMapper实现JSON与JavaBean之间的高效转换。ObjectMapper是Jackson库的核心组件,能够便捷地将Java对象序列化为JSON格式,并支持从JSON、XML以及文件等多种数据源反序列化为Java对象。此外,还探讨了在实际应用中如何优化转换性能,以提升系统整体效率。 ... [详细]
  • DAO(Data Access Object)模式是一种用于抽象和封装所有对数据库或其他持久化机制访问的方法,它通过提供一个统一的接口来隐藏底层数据访问的复杂性。 ... [详细]
  • C#实现文件的压缩与解压
    2019独角兽企业重金招聘Python工程师标准一、准备工作1、下载ICSharpCode.SharpZipLib.dll文件2、项目中引用这个dll二、文件压缩与解压共用类 ... [详细]
  • 本文介绍了在 Java 编程中遇到的一个常见错误:对象无法转换为 long 类型,并提供了详细的解决方案。 ... [详细]
  • 如何在Java中使用DButils类
    这期内容当中小编将会给大家带来有关如何在Java中使用DButils类,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。D ... [详细]
  • 本指南从零开始介绍Scala编程语言的基础知识,重点讲解了Scala解释器REPL(读取-求值-打印-循环)的使用方法。REPL是Scala开发中的重要工具,能够帮助初学者快速理解和实践Scala的基本语法和特性。通过详细的示例和练习,读者将能够熟练掌握Scala的基础概念和编程技巧。 ... [详细]
  • 目录预备知识导包构建数据集神经网络结构训练测试精度可视化计算模型精度损失可视化输出网络结构信息训练神经网络定义参数载入数据载入神经网络结构、损失及优化训练及测试损失、精度可视化qu ... [详细]
  • 第十九天 - 类的约束、异常处理与日志记录
    本文介绍了如何通过类的约束来确保代码的一致性,以及如何使用异常处理和日志记录来提高代码的健壮性和可维护性。具体包括抛出异常、使用抽象类和方法,以及异常处理和日志记录的详细示例。 ... [详细]
  • 本文总结了Java初学者需要掌握的六大核心知识点,帮助你更好地理解和应用Java编程。无论你是刚刚入门还是希望巩固基础,这些知识点都是必不可少的。 ... [详细]
  • Android 自定义 RecycleView 左滑上下分层示例代码
    为了满足项目需求,需要在多个场景中实现左滑删除功能,并且后续可能在列表项中增加其他功能。虽然网络上有很多左滑删除的示例,但大多数封装不够完善。因此,我们尝试自己封装一个更加灵活和通用的解决方案。 ... [详细]
  • JUC(三):深入解析AQS
    本文详细介绍了Java并发工具包中的核心类AQS(AbstractQueuedSynchronizer),包括其基本概念、数据结构、源码分析及核心方法的实现。 ... [详细]
  • 在多线程并发环境中,普通变量的操作往往是线程不安全的。本文通过一个简单的例子,展示了如何使用 AtomicInteger 类及其核心的 CAS 无锁算法来保证线程安全。 ... [详细]
  • Java高并发与多线程(二):线程的实现方式详解
    本文将深入探讨Java中线程的三种主要实现方式,包括继承Thread类、实现Runnable接口和实现Callable接口,并分析它们之间的异同及其应用场景。 ... [详细]
  • 大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式
    大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式 ... [详细]
  • 类加载机制是Java虚拟机运行时的重要组成部分。本文深入解析了类加载过程的第二阶段,详细阐述了从类被加载到虚拟机内存开始,直至其从内存中卸载的整个生命周期。这一过程中,类经历了加载(Loading)、验证(Verification)等多个关键步骤。通过具体的实例和代码示例,本文探讨了每个阶段的具体操作和潜在问题,帮助读者全面理解类加载机制的内部运作。 ... [详细]
author-avatar
勇气的爱_961
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有