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


    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)			//ok
    
    def 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>T getMiddle(List<T>list){
      return list.get(list.size()/2);
    }
    //调用java里面的泛型
    【Maven】
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
    </dependency>
    @Test
    public void testMethod(){
       List<Integer>list=new ArrayList<Integer>();
       list.add(1);
       list.add(2);
       list.add(3);
       list.add(4);
      System.out.println(getMiddle(list)); //2
    }
    //在方法调用中指定类型,通过对象来调用
    public static <T>T getMiddle(List<T>list){
      return list.get(list.size()/2);
    }
    @Test
    public void testMethod(){
       List<Integer>list=new ArrayList<Integer>();
       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作为一个泛型,在方法体中first.compareTo(second)<0)小于他,小于0就返回。就是T或者first是否有没有这个方法?它不一定有。所以它可能是错的。为了保证它一定有可以添加添加一个上界T<:Comparable[T]>  上限,就是要小于T<:Comparable[T]> 
      def smaller=if(first.compareTo(second)<0)first else second //错误
    }
    这是错的----我们并不知道first是否有compareTo方法。要解决这个问题,我们可以添加一个上界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){
      //定义一个方法要取,取它两个大的值。T
      //获取两个属性中较大的一个
      def max():T={
        if(first.compareTo(second)>0)first else second;
      }
    }
    val p1=new Pair(100,200)//报错,它不能比较大小在scala中它并没有Comparable
    val p1=new Pair("100","200")//200
    //注意了在Java里面和scala里面字符窗String 有什么区别
    type String =java.lang,String //scala里面的串就是java里面的串,它就是一个别名
    type Class[T]=java.lang.Class[T]
    println(p1.max()) 
    Int的是AnyVal,Int的不是别名。它没有Comparable的特点。所以它比较不了。
    如果要向实现数字的大小比较,需要用到视图界定
    [Int的源码翻看]
    final abstract class Int private etends AnyVal{}
    //考察下界
    class Animal
    class Dog extends Animal
    class Jing8 extends Dog
    //T,没有任何说法,什么都可以
    //Pari是有两个属性的,都是T类型.现在添加一个方法将first替换掉,保留第二个不变第一个变掉
    class Pair[T](var first :T,var second:T){
      //R需要是T的超类
      //def replaceFirst[R >:T](newele:R)={
      def replaceFirst[R >:T](newfirst:R)={
        //new Pair(newele,second)
        new Pair(newfirst,second)
      }
    }
    val d1=new Dog()
    val d2=new Dog()
    val p1=new Pair[Dog](d1,d2)
    val jing8=new Jing8()
    val p2= p1.replaceFirst(jing8)
    //加了泛型它就有要求,需要给方法显示指定泛型
    val p2= p1.replaceFirst[Jing8](jing8)
    //给它一个新的类型
    val a1=new Animal()
    p1.replaceFirst[Animal](a1)
    println(p2)
    
    1.类上泛型
    	class Pair[T,S](var first:T , var second:S) 
    	val p = new Pair[Int,String](100,"tom")
    	val p = new Pair(100,"tom")
    
    2.方法上泛型
    	def mid[T](arr:Array[T]) = 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 = 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) ;表示下界,R必须是父类才可以
    			new Pair(ele , sec) ;//把原sec放这替换ele
    		}
    	}
    
    	val d1 = new Dog()
    	val d2 = new Dog()
    	val p1 = new Pair(d1,d2)//
    	val jing8 = new Jing8()
    	//错误,jing8是dog的子类,不符合下界范围
    	p1.replaceFirst[Jing8](jing8)//替换,必须要把泛型写上[Jing8]
    
    	val a1 = new Animal()
    	//OK , 符合下界范围
    	p1.replaceFirst[Animal](a1)
    

    3.视图界定

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

    4.多重界定

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

    5.型变

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

    6.隐式转换

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

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

    7.SAM

    SAM(函数在java里面就是接口)(隐式转换函数的应用)
    	single abstract method(单个抽象方法)
    object SAMDemo{
      //每次实现奇数加1
      var click:Int=0
      def main(args:Array[String]):Unit={
        val frame=new JFrame()
        frame.setTitle("hello swing")
        frame.setBounds(50,50,200,100)
        frame.setVisible(true)
        //加按钮之前设置一下布局为空
        frame.setLayout(null);
        val btn=new JButton()
        btn.setBounds(0,0,100,50)
        btn.setText("ok")
        //实现点击一下加1
        btn.addActionListener(new ActionListener{
          //ActionListener  public interface ActionListener extends EventListener 它就一个  public void actionPerformed(ActionEvent e)抽象方法。。典型的匿名类对象
          override def actionPerformed(e:ActionEvent)={//常规的Java实现
            //给按钮一个点击事件,每次点击一下加1 ,scala可以做sam抽象,一个抽象方法
            click+=1
            println(click) //1,2,3,,4,5,6,,7,....15
          }
        })
        //(e:ActionEvent)=>{click_+=1;println(click)这个传的是一个函数,而不是需要的事件监听器。为了让这种方式成为可能,就要做一个隐式转换。隐式转换就是直接能把(e:ActionEvent)=>{click_+=1;println(click)转换成ActionListener实现就可可以了
       // btn.addActionListener((e:ActionEvent)=>{click_+=1;println(click)})
        //从函数到func2ActionLisnter的转换func2ActionLisnter()的参数是一个函数,{click_+=1;println(click)函数本身没有返回值。参数是ActionEvent类型
        //定义隐式转换函数,将函数转换成actionListen对象(SAM转换)
        implicit def func2ActionListnter(f:(ActionEvent)=>Unit)={
          new ActionListener{
            override def actionPerformed(e:ActionEevent)={
              f(e)
            }
          }
        }
        btn.addActionListener((e:ActionEvent)=>{click+=1;println(click)});
        frame.add(btn)
        //
        frame.setVisible(true)
      }
    }
    
  • 相关阅读:
    最全前端面试题
    经常犯的思维误区
    鸿蒙系统发布会
    前端面试题
    怎么做一个竖排文字?
    canvas-台球玩法
    canvas-自由落体球
    canvas-画一颗心
    canvas-学写字
    常用的65条正则表达式
  • 原文地址:https://www.cnblogs.com/SteveDZC/p/9771241.html
Copyright © 2020-2023  润新知