1, Object oriented
1. Class and object details
(1) Class composition structure
Constructor, member variable, member method (function), local variable, code block, internal class
(2) Constructor
- scala has two types of constructors: primary and secondary
- The main constructor follows the class name, such as class Student2(val name: String, var age: Int). If the class name is not followed by parentheses or there are no parameters in parentheses, it is an empty parameter main constructor
- Auxiliary constructor is a special method defined in the class def this(name:String,age:Int,gender:String)
- In the auxiliary constructor, the first line must call another constructor
- The parameters of the auxiliary constructor cannot be completely consistent with those of the main constructor (number of parameters, parameter type, parameter order)
- An auxiliary constructor with null parameters can be defined, but the parameters of the main constructor must be initialized and assigned
- When creating an instance of a class, you can call any constructor
- Scope: the scope of the auxiliary constructor is only in the method. The scope of the main constructor is all the scope in the class except for the member attribute and member method (you can view the source code through decompilation)
- If the parameters of the main constructor are not decorated with var/val, their parameters are local variables and can only be used in this class
- The parameter of the constructor modified by val is the member attribute of the class, which is read-only
- The parameter of the constructor modified by var is the member attribute of the class, but it is readable and writable
Note: the main constructor executes all statements in the class definition. It is equivalent that the whole class is in the main constructor
class User { // Class has a parameterless primary constructor by default} val user = new User
class User3 { var name: String = _ var age: Int = _ // Auxiliary constructor def this(name: String, age: Int) { // The first line in the constructor must call the main constructor or another constructor this() this.name = name this.age = age } // Auxiliary constructor def this(msg: String) = { // The first line calls a construct this("ww", 12) println(msg) } } val u1 = new User3() val u2 = new User3("") val u3 = new User3("lisi", 23) println(u3.name)
(3) Member variable
- Variables decorated with val and var in the main constructor are member variables
- Variables defined in a class are also member variables
- The variable modified by val has only getter method to initialize by default
- var modified variables have get and set methods by default, and are used directly for point attribute operations_ The placeholder can be assigned later
- Using @ BeanProperty on a member variable generates the getMsg setMsg method
// 1. The variables modified with val and var in the main constructor are member variables class Person(val address:String) { // 2. The variable modified by Val has only getter method to initialize by default val name:String = "val Modifier must be assigned here" // 3. Var modified variables have get and set methods by default, and are used for direct point attribute operations_ The placeholder can be assigned later var age:Int= _ // The placeholder can be assigned later // 4 @BeanProperty will generate getMsg setMsg method @BeanProperty var msg:String = _ }
(4) Member methods / functions
A function or method defined at the member position of a class is part of the member of the class
(5) Local variable
The parameters defined in the function / method are defined in the code block, and the variables defined in the conditional expression of process control become local variables, which can only be used in the local code block
(6) Code block
The code block in the class is executed once every time it is instantiated (created).
The code block in the associated object is a static code block, which is executed only once when the class is loaded and will not be executed after that.
(7) Associated classes and associated objects
Condition 1: in the same source file, condition 2: the object name and class name are the same
class Demo{ val id = 1 private var name = "xiaoqing" def printName(): Unit ={ //In the Dog class, you can access the private properties of the associated object Dog println(Demo.CONSTANT + name ) } } /** * Companion Object */ object Demo{ //Private properties in companion objects private val CONSTANT = "Woof, woof : " def main(args: Array[String]) { val p = new Demo //Access private field name p.name = "123" p.printName() } }
Associated objects and associated classes can access each other's private properties and private methods
(8) apply method
The apply method is a special method. When calling, you only need to pass in parameters without writing the method name
class Demo1 { //Define the apply method in the half life class of Demo1 def apply() { println("This is a class") } } object Demo1 { //Define the apply method in the half life object of Demo1 def apply() { println("This is the object") } } object Demo2 { def main(args: Array[String]): Unit = { val demo = new Demo1() //Call the apply method in the half life class demo() //Output: This is a class //Call the apply method in the half life object Demo1() //Output: This is an object } }
be careful:
- The main purpose of the apply method is not to use new to get the instance object, and it is singleton by default!!!
- The apply method is recommended to be written in the companion object
- Do not omit () if the apply method has no parameters
(9)classOf,isInstanceOf,asInstanceOf
- classOf[T] as T.class in Java
- obj.isInstanceOf[T] judge whether it is an instance object of T
- obj.asInstanceOf[T] cast
(10) , class, object, case class, case object differences
Class is similar to class in Java;
object Scala cannot define static members, instead of defining singleton objects;
case class is called sample class. It is a special class and is often used for pattern matching.
1, Relationship between class and object:
- 1. The singleton object cannot take parameters, and the class can
- 2. When an object can have the same name as a class, object is called an associated object and class is called an associated class;
- 3. Classes and associated objects can access their private properties, but they must be in a source file;
- 4. The class will only be compiled and will not be executed. To execute, it must be in Object.
2, Difference between case class and class:
- 1.case class can be initialized without or with new, but ordinary classes must be added with new;
- 2.case class implements the equals and hashCode methods by default;
- 3.case class can be serialized by default, and Serializable is implemented;
- 4.case class automatically inherits some functions from scala.Product;
- 5. The case class constructor parameter is public and can be accessed directly;
- 6.case class attribute values cannot be modified by default;
- 7. The most important function of case class is to support pattern matching, which is also an important reason for defining case class.
3, Difference between case class and case object:
- 1. There are parameters and no parameters in the class. When the class has parameters, use case class. When the class has no parameters, use case object.
4, When a class is called case class, scala will help us do the following things:
- 1. If the parameter in the constructor is not declared as var, it is of type val by default, but it is generally not recommended to declare the parameter in the constructor as var
- 2. Automatically create the associated object and implement the sub apply method in it, so that we can use the new object without directly displaying it
- 3. The associated objects will also help us implement the unapply method, so that we can apply the case class to pattern matching. We will focus on the unapply method in the "extractor" section later
- 4. Implement your own toString, hashCode, copy and equals methods
- In addition, case class is no different from other ordinary scala classes
2. Permission modifier
The permission modifiers in scala include public, protected and private. By default, public is used and can be accessed in any range
The attributes and methods modified by protected are valid in the class and its associated objects, valid in the associated objects of subclasses and their subclasses, and invalid elsewhere.
The access scope of the property or method modified by private is in this class and associated objects
scala has more strict access control
- private [this] scope is in the current class, and the associated object cannot be accessed
- private [packageName] specifies that the package and its sub packages are valid. The writing method of package name is to write the registration directly without hierarchical path. Note: you cannot write the package name at the same level as the current package. You can only write the current package or the parent package and grandfather package of the current package
It is common for classes, main constructors, auxiliary constructors, properties in main constructors, properties in classes, and methods in classes
3. Idiosyncrasy
(1) Trait use
Trait is equivalent to the interface of java. More powerful than the interface.
Attributes, abstract methods and ordinary methods (Methods with concrete implementation) can be defined in attributes. The implementation class needs to implement all abstract methods. It will inherit the properties and ordinary methods in the characteristics and can be called directly.
Scala's classes can only inherit a single parent class, but can implement (inherit, mix in) multiple traits
There are no implements in scala, and extensions and with are used to implement multiple attributes
with can only be followed by traits
Note that attributes cannot have a primary constructor
//Trait 1 trait T1 { val name:String = "I am a trait" def add(x:Int) def show(desc:String)={ println(desc) } } // Trait 2 trait T2{ def show() } // Realize multiple characteristics class Demo extends T1 with T2{ // Implementing abstract methods in interfaces override def add(x:Int): Unit = { } // The override keyword for implementing abstract methods can be omitted def show(): Unit = {} }
(2) Dynamic blending of traits
Dynamic blending: inherit the characteristics and implement the corresponding methods when creating the instance object.
Use with traits to blend in traits when creating objects
You can mix multiple traits with trait 1 and trait 2 to rewrite the abstract method of all traits
class A { } class B{ def haha={ // Dynamic mixing implements the specific interface and rewrites the corresponding abstract method when it is used val a = new A with T1 with T2 { override def add(x: Int): Unit = ??? override def show(): Unit = ??? } } }
4. Abstract class
In Scala, classes decorated with abstract are called abstract classes.
Attributes, unimplemented methods (abstract methods) and concretely implemented methods can be defined in abstract classes.
Abstract classes can have no abstract methods. Classes with abstract methods must be abstract classes
Class can only inherit one abstract class, and with can only be followed by traits
//The class modified by abstract is an abstract class abstract class Animal { println("Animal's constructor ....") // Define a name attribute val name: String = "animal" // There is no way to implement it def sleep() // Method with specific implementation def eat(f: String): Unit = { println(s"$f") }}
5. Sample class
The class decorated with case is the sample class
- The parameters in the constructor are val decorated by default
- The sample class will automatically create the companion object, and implement the apply and unapply methods in it. new is not used when creating the object
- Good support for matching patterns
- By default, it implements its own toString, hashcode, copy and equals methods
// Define a sample class case class Person(name:String , var age:Int) { }
Some differences between case class and class:
- When initializing a case class, you do not need new, but when initializing an ordinary class, you must use new.
- case class overrides the toString method. equals and hashCode are implemented by default
- case class implements the serialization interface with Serializable
- Case classes support pattern matching (the most important feature). All case class es must have a parameter list
- Use case class for parameters and case object for none
- case class and case object can be passed as messages
2, Advanced Grammar
1. Higher order function
- The parameter of a function is the function or method of the function
- The return value of a function is the function or method of the function
- The parameters and return values of a function are the functions or methods of the function
The argument to a function or method is a function
map, filter and other methods take functions as parameters
//Pass the function as an argument val c=(a : Int,b: Int,f:(Int,Int)=>Int) => { f(a,b) } //This allows the user to define the processing logic println(c(3, 4, (x: Int, y: Int) => x + y )) println(c(3, 4, (x: Int, y: Int) => x * y ))
The return value of the function is the function
def urlBuilder(ssl: Boolean, domainName: String): (String, String) => String = { val schema = if (ssl) "https://" else "http://" (endpoint: String, query: String) => s"$schema$domainName/$endpoint?$query" } val domainName = "www.example.com" //Get return function def getURL = urlBuilder(ssl=true, domainName) val endpoint = "users" val query = "id=1" val url = getURL(endpoint, query) // "https://www.example.com/users?id=1": String
2. Partial function
Partial function is a characteristic, which is specially used to deal with one type of data
// Implementation of partial function in the form of filter val list = List(1, 2, 3, 4, "hello") val res: List[Int] = list.filter(x => x.isInstanceOf[Int]).map(x => x.asInstanceOf[Int] + 1) res.foreach(println) // Mode 2 matching mode val res2: List[Any] = list.map(x => x match { //int type plus 1 case x: Int => x + 1 //Others are not handled case _ => }) res2.filter(x => x.isInstanceOf[Int]).foreach(println) // Method 3 uses the data type input by partial function parameter 1 and the data type returned by parameter 2 val pp = new PartialFunction[Any,Int] { // Return true override def isDefinedAt(x: Any) = { x.isInstanceOf[Int] } // Execute next method override def apply(v1: Any) = { v1.asInstanceOf[Int]+1 } } // list.map(pp).foreach(println) list.collect(pp).foreach(println)
- PartialFunction is a trait (see the source code)
- When constructing a partial function, the parameter form [Any, Int] is generic. The first represents the type of input parameter and the second represents the data type of returned data
- When partial functions are used, all elements of the collection will be traversed. When the compiler executes the process, it first executes isDefinedAt(). If it is true, it will execute apply and build a new Int object to return
- If isDefinedAt() is false, this element will be filtered out, that is, no new Int object will be built
- The map function does not support partial functions, because the underlying mechanism of the map is all loop traversal, and the elements of the original collection cannot be filtered
- The collect function supports partial functions
Partial function abbreviation
//The return type of the defined function is PartialFunction def myPartialFunction: PartialFunction[Any, Int] = { case x: Int => x * x } //Use matching patterns directly in the collect() method list.collect({case x:Int=>x*x}).foreach(println)
3. Matching pattern
Pattern matching is actually similar to the swich case syntax in Java, that is, conditional judgment is performed on a value, and then different processing is performed for different conditions.
However, Scala's pattern matching function is much more powerful than Java's swich case syntax, which can only match values. However, in addition to matching values, Scala's pattern matching can also match types, elements of Array and List, case class es, and even options with or without values.
For spark, the pattern matching function of Scala is also extremely important. The pattern matching function is widely used in the spark source code.
Basic syntax:
_ match { case _ 2 => TODO case _1 => TODO case _ => }
(1) Value matching
val str:String = "111" str match { case "111" => println("111") case "222" => println("222") }
(2) Data type matching
val arr = Array(1,"a",1.40) // Generate a random integer data and randomly fetch an element in the array val index = Random.nextInt(arr.length) arr(index) match { case x:Int => println(s"This is a Int Value of type $x") case x:String => println(s"This is a String Value of type $x") case x:Double => println(s"This is a Double Value of type $x") // You can match collection types and data types case x:Array[Int]=>println("This is an array") case x:List[String]=>println("List aggregate") case x:Map[String,Int]=>println("map aggregate") case x:MyUser=>println("MyUser") case _ =>println("I don't know what type") }
(3) Internal data structure analysis
tuple
val tap: ((String), (Int), (String)) = Tuple3("3",1,"2") tap match { //Number of matching tuple elements case Tuple3(_,_,_) => println(s"This is a tuple") //Match the number of tuple elements and get the first value case (x,_,_) => println(s"This is a tuple+$x") //Match the tuple with the first value of 3 and the number of elements of 3 case ("3",x,_) => println(s"This is a tuple+$x") //Number of matching tuple elements and element type case (x:String,y:Int,z:String) => println(s"This is a tuple+$x") }
Array
val arr1: Array[Any] = Array[Any]("abc",12,3,4,5,6) arr1 match { //Match the number of array elements and get the first value case Array(x,_,_,_,_,_) => print(s"$x") //Number and type of matched array elements case Array(x:String,_,_,_,_,_) => print(s"$x") //Matches an array with 'abc' as the first element case Array("abc",_*) =>print("This array is expressed as a string abc start : "+arr.length) //Take this when none of the above meets the requirements case _ => println("hah") }
List
x match { //Matches a List with only one element case head::Nil => println(s"With only one element Lis") case List(_) => println(s"With only one element Lis") case List(x) => println(s"With only one element Lis") //Number of matching List elements case List(_,_,x,_,_,_) =>println(s"With 5 elements list The third position is $x") case head::second::thr::Nil =>println(s"3 Of elements list The first element of the collection is $head") //Match List element type case List(x:Int,_*) => println(s"with $x initial List") //Match List specified elements case List(1,_*) => println(s"Beginning with 1 List") //In this way, you can match all list elements. Head is the first element, tail is the second element, and a is all the remaining elements case head::tail::a => println(s"$a") }
Sample class
val user =User(1,"zss",13) user match { case User(_,_,_) => case User(1,_,_) => case User(x:Int,y:String,z:Int) => }
Option
val map = Map("yangzi"->27,"reba"->30 ,"yangmi"->41) val res: Int = map.get("fengjie") match { case Some(v) => v case None => -1 }
Map collections and custom classes do not support pattern matching structure resolution because structure resolution is essentially implemented by calling the unapply method of the original class. The sample class implements the unapply method by default and supports structure parsing.
4. Closure
A closure is a function whose return value depends on one or more variables declared outside the function.
Generally speaking, closures can be simply regarded as another function that can access local variables in a function.
var factor = 3 val multiplier = (i:Int) => i * factor
There are two variables in the multiplier: i and factor. One i is the formal parameter of the function. When the multiplier function is called, i is given a new value. However, factor is not a formal parameter, but a free variable, which is defined outside the function.
The function variable multiplier thus defined becomes a "closure" because it refers to the variables defined outside the function. The process of defining the function is to capture the free variable to form a closed function.
5. Detailed explanation of Coriolis
A function with multiple parameter lists is a coriolised function. The so-called parameter list is a list of function parameters enclosed in parentheses
The greatest significance of curry is to transform the function equivalence of multiple parameters into the cascade of multiple single parameter functions, so that all functions are unified and convenient for lambda calculus. In scala, curry is also helpful for type deduction. scala's type deduction is local. In the same parameter list, the subsequent parameters cannot be deduced with the help of the previous parameter types. After curry, they are placed in two parameter lists, and the parameters in the latter parameter list can be deduced with the help of the parameter types in the previous parameter list. This is why the definition of foldLeft is curry
Advantages of Coriolis function:
- Facilitate type derivation and data evolution
//Pass in a list to find whether there are qualified values in the list def findElement[T](ls: List[T], f: T => Boolean): Option[T] = { ls match { case Nil => None case head :: tail => if (f(head)) Some(head) else findElement(tail, f) } } //Corellized form def findElement2[T](ls: List[T])(f: T => Boolean): Option[T] = { ls match { case Nil => None case head :: tail => if (f(head)) Some(head) else findElement2(tail)(f) } } //Common methods cannot calculate their own type from the contents of the previous List[Int]. The type must be specified after int E val opt: Option[Int] = findElement(List[Int](1, 2, 3, 4, 5, 6), (e: Int) => e > 2) //The Coriolis method will calculate that its type is int e according to the contents of the previous List[Int], and there is no need to specify the type val opt2: Option[Int] = findElement2(List[Int](1, 2, 3, 4, 5, 6))((e) => e > 2) opt2 match { case None => println("No value") case Some(value) => println(s"The element found is: $value") }
- Reduce parameter passing of methods
def mkSal(deptno:Int , sal:Int)(comm:Int):Int={ deptno+sal+comm } //When the parameters in the preceding parentheses remain unchanged, you can no longer pass the preceding parameters val f: Int => Int = mkSal(1, 2) println(f(3)) println(f(4))
- Separate data from processing logic
def add(x:Int,y:Int)(f:(Int,Int)=>Int):Int={ f(x,y) } val f: ((Int, Int) => Int) => Int = add(1, 2) val i1: Int = f(_ + _) val i2: Int = f(_ - _)
5. Implicit explanation
The content decorated with implicit is implicit content. The implicit feature is that it will be automatically applied when encountering an adaptive type
significance:
- Make static types dynamic
- Add functionality to an existing class library
- Implicit proxies enhance a class or method
All implicit values and implicit methods must be placed in the object.
(1) Implicit variable
If two matching implicit variables are found in the scope, an error will be reported, so there can be no implicit variables of the same type in the scope
If a method has multiple parameters, to realize the implicit conversion of some parameters, you must use Coriolis. The implicit keyword appears later and can only appear once
//Implicit variables variables modified with implicit are implicit variables implicit val str1 = "java Basic teacher" implicit val age= 32 def show(name:String)(implicit msg:String,age:Int): Unit ={ println(s"$name yes $msg,this year $age Years old") } //Implicit parameters can be passed automatically without passing during method call: the premise is that a corresponding implicit variable can be found from the context show("zss")
(2) Implicit conversion
When the Scala compiler performs type matching, if no suitable candidate can be found, implicit conversion provides another way to tell the compiler how to convert the current type to the expected type.
The core is to define the implicit conversion function. According to the signature of the implicit conversion method, Scala will automatically transfer the object defined by the parameter type received by the implicit conversion method into the implicit conversion method, convert it into another type of object and return it.
When is implicit conversion required?
- When an object calls a method or member that does not exist in the class, the compiler automatically implicitly converts the object
- When the parameter type in the method is inconsistent with the target type
Limitations of implicit conversion:
- implicit keyword can only be used to modify methods and variables (parameters)
- The method of implicit conversion is valid only in the current scope. If the implicit method is not defined in the current scope (for example, it is defined in another class or contained in an object), it must be imported through the import statement
(3) Implicit function
An implicit function is only related to the parameter type and return type of the function, not the function name. Therefore, there cannot be implicit functions with different names of the same parameter type and return type in the scope.
// Implicit function when using File, it is found that there is an implicit conversion of File = > bufferedsource method in the context // Enhance and extend the function items of the class implicit def richFile(file:File): BufferedSource ={ val bs: BufferedSource = Source.fromFile(file) bs } val file = new File("d://user.txt") //The implicit conversion file can directly call the BufferedSource method getLines val lines: Iterator[String] = file.getLines()
Method has an implicit function in its argument list
When calling a method, the compiler can automatically call the defined implicit function without passing a function, or pass in a user-defined function
//implicit function implicit def add(x:String,y:Int): String ={ x+y } //The parameters of normal functions use implicit parameters or implicit functions def m1 ( x:Int, y:String)(implicit f:(String,Int)=>String):String={ f(y,x) } println(m1(10, "nihao"))//Output: nihao10
(4) Implicit class
Similar to decorator mode, wrap a class to enhance its functionality
Implicit class constraints
- An implicit class must have a primary constructor with one argument
- Must be defined in another class/object/trait (cannot be defined independently)
- An implicit class constructor can only take one parameter that is not an implicit modifier
- The scope cannot have the same member variable, function and object name as the implicit class type
object ImplicitContext{ //An implicit class can only enhance one type of class, class B or subclass implicit class RichB(b:B){ def multiply(x: Int, y: Int) = { x * y } } } class B { val add = (x: Int, y: Int) => { x + y } } def main(args: Array[String]): Unit = { val b = new B // Class B and its subclasses //Call your own method println(b.add(12, 12)) //Introducing implicit classes import ImplicitContext._ //Calling methods of implicit classes println(b.multiply(12, 12)) }
(5) Using implicit transformation to sort custom classes
Defining an implicit comparator Ordering
implicit val ording: Ordering[User] = new Ordering[User] { override def compare(x: User, y: User): Int = { y.age - x.age } } val users = List(new User(1, "zss", 13), new User(2, "lss", 23)) //When the sorted method is called, the comparator is implicitly passed in as a parameter println(users.sorted)
Define an implicit method to convert User to Ordered
Note: this method cannot get the attribute value in the compare method
implicit def UserSored[User](user:User): Ordered[User] = { new Ordered[User] { override def compare(that: User): Int = { -(that.hashCode() - user.hashCode()) } } } val users = List(new User(1, "zss", 13), new User(2, "lss", 23)) //When the sorted method is called, the User is implicitly converted to Ordered println(users.sorted)
Defining implicit functions using generics
implicit def t2Com[T](t:T):Ordered[T]={ new Ordered[T] { override def compare(that: T): Int = that.hashCode() - t.hashCode() } } //Use implicit functions in methods def max[T](x:T,y:T)(implicit order:T=>Ordered[T]): T ={ if(x > y) x else y } //You can also not write implicit parameters, which will be automatically implicitly converted def max[T](x:T,y:T) ={ if(x > y) x else y }
6. Generic explanation
Scala's generics are similar to those in java. Generics can be defined on classes, methods and attributes to constrain types!
If we require that the parameters of the function can accept any type. You can also use generics, which can represent any data type.
(1) Generic class
//Define generics on classes class GenericClass[K,V](k:K,v:V) { def show(): Unit ={ println(k+"----->"+v) } } object Test1{ def main(args: Array[String]): Unit = { // You do not need to specify a type for automatic inference val gc = new GenericClass("Jack",999.99) // Specify type val gc1 = new GenericClass[String , String]("jim", "cat") // Specify the type. If the incoming data matches the type, an error will be reported val gc2 = new GenericClass[String , Int]("jim", "cat") gc.show() } }
(2) Generic method
To use generics in a method, you must first define generics after the method name
// Find the maximum of two numbers int double float // Define generic methods to receive arbitrary data types def max[T](x:T,y:T): T ={ if(x > y) x else y } // Use the implicit function to convert t into a name T type that can be compared. You can use > to compare implicit def t2Com[T](t:T):Ordered[T]={ new Ordered[T] { override def compare(that: T): Int = t.hashCode() - that.hashCode() } }
// Receive a collection List of any type to get the data of all even index positions def getElements[E](ls:List[E]): List[E] ={ val es = for (elem <- 0 to ls.length - 1 if elem % 2 == 0) yield ls(elem) es.toList } val res1: List[Int] = getElements[Int](List[Int](1, 3, 5, 7, 9, 2, 4, 6, 8)) val res2: List[String] = getElements[String](List[String]("tom","jim","cat","rose"))
(3) Generic upper and lower bounds
Upper and lower bounds in java:
- < T extends a > type A is the upper bound
- < T super a > type A is the lower bound
Upper and lower bounds in Scala
- Upper bound [T <: a] type A is the upper bound, and the incoming type must be type A and its subclasses
- Lower bound [t >: a] type A is the lower bound, and the passed in type must be type A and its parent class
If the upper bound of the generic is defined as the Ordered class, the generic objects can be compared
// B is the upper bound. The upper bound parameter must be the specified type and its subtypes def test1[T <:B](t:T): Unit ={ } // B is the lower bound, and the parameter is the specified type and its parent type def test2[T >:B](t:T){ } class A extends B class B { } class C { } test1(new A) test1(new B) test1(new C) //Error C is not a subtype of B //After specifying the lower bound, the following writing method will not report an error, because [] does not write. The default is Any, which is the parent of all classes test2(new A) //Writing like this will report an error test2[A](new A)
(4) Context definition
When the implicit parameters are explained, an implicit parameter is needed to implicitly convert the type in the generic type to the corresponding type
def myMax(x1:T,x2:T)(implicit o:T=>Ordered[T])={ if(x1 > x2) x1 else x2 }
7,IO
(1) Input
Get input file source: Source.fromFile("")
(1) Input line
object LineIO { def main(args: Array[String]): Unit = { // read file val bs: BufferedSource = Source.fromFile("d://data.txt") // Get all rows val lines: Iterator[String] = bs.getLines() // Traverse all rows for (line <- lines) { println(line) } // Row list val list: List[String] = lines.toList //Row array val array: Array[String] = lines.toArray // Entire string val content: String = lines.mkString // Release resources bs.close() } }
(2) Input byte
object ByteIo { def main(args: Array[String]): Unit = { val bs: BufferedSource = Source.fromFile("d://data.txt") // Get input stream object val reader: InputStreamReader = bs.reader() //Skip the specified length to the specified position reader.skip(1) // Read a byte val byte: Int = reader.read() println(byte) // 99 reader.close() bs.close() } }
def main(args:Array[String]):Unit={ val file = new File("F:\\info.bin") val in = new FileInputStream(file) val bytes = new Array[Byte](file.length.toInt) in.read(bytes) in.close }
(3) Read other data sources
//Read from URL val source= Source.fromURL("http://www.baidu.com","UTF-8") val lineIterator =source.getLines for(l<-lineIterator){ println(l.toString()) }
//Read from the given string -- useful for debugging val source2= Source.fromString("Hello DOIT") println(source2.mkString)//Hello DOIT
//Read from standard input val in: BufferedReader = Console.in println(in.readLine())
(2) Output
//Append when True val out = new FileWriter("D:\\index.txt",true) for (i <- 0 to 15){ out.write(i.toString) out.append"111") out.close()
val writer = new PrintWriter("D:\\index.txt") for(i <- 1 to 10) writer.println(i)// This is auto wrap. Don't add any more \ remember writer.write("111") writer.append("111") writer.close()