Scala Language
वर्ग और वस्तुएँ
खोज…
वाक्य - विन्यास
-
class MyClass{} // curly braces are optional here as class body is empty
-
class MyClassWithMethod {def method: MyClass = ???}
-
new MyClass() //Instantiate
-
object MyObject // Singleton object
-
class MyClassWithGenericParameters[V1, V2](vl: V1, i: Int, v2: V2)
-
class MyClassWithImplicitFieldCreation[V1](val v1: V1, val i: Int)
-
new MyClassWithGenericParameters(2.3, 4, 5)
या एक अलग प्रकार के साथ:new MyClassWithGenericParameters[Double, Any](2.3, 4, 5)
-
class MyClassWithProtectedConstructor protected[my.pack.age](s: String)
त्वरित श्रेणी उदाहरण
स्काला में एक वर्ग एक श्रेणी उदाहरण का 'खाका' है। एक उदाहरण में उस वर्ग द्वारा परिभाषित स्थिति और व्यवहार होता है। एक वर्ग घोषित करने के लिए:
class MyClass{} // curly braces are optional here as class body is empty
एक उदाहरण new
कीवर्ड का उपयोग करके तत्काल किया जा सकता है:
var instance = new MyClass()
या:
var instance = new MyClass
कोष्ठक Scala में वैकल्पिक हैं एक वर्ग से ऑब्जेक्ट बनाने के लिए जिसमें कोई तर्क नहीं है। यदि कोई क्लास कंस्ट्रक्टर तर्क देता है:
class MyClass(arg : Int) // Class definition
var instance = new MyClass(2) // Instance instantiation
instance.arg // not allowed
यहाँ MyClass
को एक Int
तर्क की आवश्यकता होती है, जिसका उपयोग केवल कक्षा में आंतरिक रूप से किया जा सकता है। जब तक इसे फ़ील्ड के रूप में घोषित नहीं किया जाता तब तक MyClass
बाहर arg
को एक्सेस नहीं किया जा सकता:
class MyClass(arg : Int){
val prop = arg // Class field declaration
}
var obj = new MyClass(2)
obj.prop // legal statement
वैकल्पिक रूप से इसे निर्माता में सार्वजनिक घोषित किया जा सकता है:
class MyClass(val arg : Int) // Class definition with arg declared public
var instance = new MyClass(2) // Instance instantiation
instance.arg //arg is now visible to clients
बिना पैरामीटर वाले तात्कालिक वर्ग: {} बनाम ()
मान लीजिए कि हमारे पास एक वर्ग MyClass है जिसमें कोई निर्माता तर्क नहीं है:
class MyClass
स्काला में हम इसे सिंटैक्स के नीचे प्रयोग कर सकते हैं:
val obj = new MyClass()
या हम बस लिख सकते हैं:
val obj = new MyClass
लेकिन, अगर ध्यान न दिया जाए, तो कुछ मामलों में वैकल्पिक कोष्ठक कुछ अप्रत्याशित व्यवहार पैदा कर सकता है। मान लीजिए हम एक ऐसा कार्य बनाना चाहते हैं जो एक अलग सूत्र में चलना चाहिए। नीचे नमूना कोड है:
val newThread = new Thread { new Runnable {
override def run(): Unit = {
// perform task
println("Performing task.")
}
}
}
newThread.start // prints no output
हम सोच सकते हैं कि निष्पादित किया गया यह नमूना कोड Performing task.
को प्रिंट करेगा Performing task.
, लेकिन हमारे आश्चर्य के लिए, यह कुछ भी प्रिंट नहीं करेगा। देखते हैं कि यहां क्या हो रहा है। यदि आप करीब से देखते हैं, तो हमने new Thread
ठीक बाद घुंघराले ब्रेस {}
उपयोग किया है। इसने एक वार्षिक वर्ग बनाया जो Thread
विस्तार करता है:
val newThread = new Thread {
//creating anonymous class extending Thread
}
और फिर इस एनॉनिमस वर्ग के शरीर में, हमने अपने कार्य को परिभाषित किया (फिर से Runnable
इंटरफ़ेस को लागू करने वाला एक अनाम वर्ग बना)। तो हमने सोचा होगा कि हमने public Thread(Runnable target)
कंस्ट्रक्टर का इस्तेमाल किया है लेकिन वास्तव में (वैकल्पिक ()
को अनदेखा करके) हमने public Thread()
कंस्ट्रक्टर का उपयोग run()
विधि के शरीर में परिभाषित कुछ भी नहीं किया है। समस्या को ठीक करने के लिए, हमें घुंघराले ब्रेसिज़ के बजाय कोष्ठक का उपयोग करने की आवश्यकता है।
val newThread = new Thread ( new Runnable {
override def run(): Unit = {
// perform task
println("Performing task.")
}
}
)
दूसरे शब्दों में, यहाँ {}
और ()
विनिमेय नहीं हैं।
सिंगलटन और साथी वस्तुएँ
सिंगलटन ऑब्जेक्ट्स
स्काला स्टेटिक सदस्यों का समर्थन करता है, लेकिन जावा के समान नहीं। स्काला इसे सिंगलटन ऑब्जेक्ट्स का विकल्प प्रदान करता है। सिंगलटन ऑब्जेक्ट्स एक सामान्य वर्ग के समान हैं, सिवाय इसके कि उन्हें new
कीवर्ड का उपयोग करके त्वरित नहीं किया जा सकता है। नीचे एक नमूना एकल वर्ग है:
object Factorial {
private val cache = Map[Int, Int]()
def getCache = cache
}
ध्यान दें कि हमने सिंगलटन ऑब्जेक्ट ('क्लास' या 'ट्रेट' के बजाय) को परिभाषित करने के लिए object
कीवर्ड का उपयोग किया है। चूंकि सिंगलटन ऑब्जेक्ट्स को तत्काल नहीं किया जा सकता है, इसलिए उनके पास पैरामीटर नहीं हो सकते हैं। एक सिंगलटन ऑब्जेक्ट तक पहुँचना इस तरह दिखता है:
Factorial.getCache() //returns the cache
ध्यान दें कि यह बिल्कुल जावा क्लास में स्टैटिक मेथड एक्सेस करने जैसा लगता है।
साथी वस्तुओं
स्काला सिंगलटन ऑब्जेक्ट में संबंधित वर्ग का नाम साझा किया जा सकता है। ऐसे परिदृश्य में सिंगलटन ऑब्जेक्ट को कंपेनियन ऑब्जेक्ट के रूप में संदर्भित किया जाता है। उदाहरण के लिए, क्लास Factorial
नीचे परिभाषित किया गया है, और इसके नीचे एक साथी ऑब्जेक्ट (जिसे Factorial
भी कहा जाता है) परिभाषित किया गया है। कन्वेंशन द्वारा साथी वस्तुओं को उनके साथी वर्ग के समान फ़ाइल में परिभाषित किया गया है।
class Factorial(num : Int) {
def fact(num : Int) : Int = if (num <= 1) 1 else (num * fact(num - 1))
def calculate() : Int = {
if (!Factorial.cache.contains(num)) { // num does not exists in cache
val output = fact(num) // calculate factorial
Factorial.cache += (num -> output) // add new value in cache
}
Factorial.cache(num)
}
}
object Factorial {
private val cache = scala.collection.mutable.Map[Int, Int]()
}
val factfive = new Factorial(5)
factfive.calculate // Calculates the factorial of 5 and stores it
factfive.calculate // uses cache this time
val factfiveagain = new Factorial(5)
factfiveagain.calculate // Also uses cache
इस उदाहरण में हम बार-बार संख्याओं के लिए गणना समय को बचाने के लिए एक संख्या के भाज्य को संग्रहीत करने के लिए एक निजी cache
का उपयोग कर रहे हैं।
यहाँ object Factorial
एक साथी ऑब्जेक्ट है और class Factorial
इसके संबंधित साथी क्लास है। साथी वस्तुओं और कक्षाएं एक-दूसरे के private
सदस्यों तक पहुंच सकते हैं। ऊपर दिए गए उदाहरण में Factorial
क्लास के निजी cache
मेंबर की पहुंच है।
ध्यान दें कि वर्ग की एक नई तात्कालिकता अभी भी उसी साथी वस्तु का उपयोग करेगी, इसलिए उस वस्तु के सदस्य चर में कोई भी संशोधन किया जाएगा।
वस्तुओं
जबकि कक्षाएं ब्लूप्रिंट की तरह अधिक होती हैं, ऑब्जेक्ट स्थिर होते हैं (अर्थात पहले से ही तत्काल):
object Dog {
def bark: String = "Raf"
}
Dog.bark() // yields "Raf"
उन्हें अक्सर एक वर्ग के साथी के रूप में उपयोग किया जाता है, वे आपको लिखने की अनुमति देते हैं:
class Dog(val name: String) {
}
object Dog {
def apply(name: String): Dog = new Dog(name)
}
val dog = Dog("Barky") // Object
val dog = new Dog("Barky") // Class
उदाहरण प्रकार की जाँच
प्रकार की जाँच करें : variable.isInstanceOf[Type]
पैटर्न मिलान के साथ (इस रूप में इतना उपयोगी नहीं):
variable match {
case _: Type => true
case _ => false
}
दोनों isInstanceOf
और पैटर्न मिलान केवल ऑब्जेक्ट के प्रकार की जांच कर रहे हैं, न कि इसके जेनेरिक पैरामीटर (कोई प्रकार का संशोधन) को छोड़कर, सरणियों के लिए:
val list: List[Any] = List(1, 2, 3) //> list : List[Any] = List(1, 2, 3)
val upcasting = list.isInstanceOf[Seq[Int]] //> upcasting : Boolean = true
val shouldBeFalse = list.isInstanceOf[List[String]]
//> shouldBeFalse : Boolean = true
परंतु
val chSeqArray: Array[CharSequence] = Array("a") //> chSeqArray : Array[CharSequence] = Array(a)
val correctlyReified = chSeqArray.isInstanceOf[Array[String]]
//> correctlyReified : Boolean = false
val stringIsACharSequence: CharSequence = "" //> stringIsACharSequence : CharSequence = ""
val sArray = Array("a") //> sArray : Array[String] = Array(a)
val correctlyReified = sArray.isInstanceOf[Array[String]]
//> correctlyReified : Boolean = true
//val arraysAreInvariantInScala: Array[CharSequence] = sArray
//Error: type mismatch; found : Array[String] required: Array[CharSequence]
//Note: String <: CharSequence, but class Array is invariant in type T.
//You may wish to investigate a wildcard type such as `_ <: CharSequence`. (SLS 3.2.10)
//Workaround:
val arraysAreInvariantInScala: Array[_ <: CharSequence] = sArray
//> arraysAreInvariantInScala : Array[_ <: CharSequence] = Array(a)
val arraysAreCovariantOnJVM = sArray.isInstanceOf[Array[CharSequence]]
//> arraysAreCovariantOnJVM : Boolean = true
टाइप कास्टिंग : variable.asInstanceOf[Type]
पैटर्न मिलान के साथ:
variable match {
case _: Type => true
}
उदाहरण:
val x = 3 //> x : Int = 3
x match {
case _: Int => true//better: do something
case _ => false
} //> res0: Boolean = true
x match {
case _: java.lang.Integer => true//better: do something
case _ => false
} //> res1: Boolean = true
x.isInstanceOf[Int] //> res2: Boolean = true
//x.isInstanceOf[java.lang.Integer]//fruitless type test: a value of type Int cannot also be a Integer
trait Valuable { def value: Int}
case class V(val value: Int) extends Valuable
val y: Valuable = V(3) //> y : Valuable = V(3)
y.isInstanceOf[V] //> res3: Boolean = true
y.asInstanceOf[V] //> res4: V = V(3)
टिप्पणी: यह केवल जेवीएम पर व्यवहार के बारे में है, अन्य प्लेटफार्मों (जेएस, देशी) पर टाइपिंग / चेकिंग अलग तरीके से व्यवहार कर सकती है।
कंस्ट्रक्टर्स
प्राथमिक कंस्ट्रक्टर
स्काला में प्राथमिक निर्माता वर्ग का शरीर है। क्लास का नाम एक पैरामीटर सूची के बाद है, जो कि कंस्ट्रक्टर तर्क हैं। (किसी भी फ़ंक्शन के साथ, एक खाली पैरामीटर सूची को छोड़ा जा सकता है।)
class Foo(x: Int, y: String) {
val xy: String = y * x
/* now xy is a public member of the class */
}
class Bar {
...
}
जब तक val
कीवर्ड द्वारा इंस्टेंस सदस्य के रूप में चिह्नित नहीं किया जाता है, उसके कंस्ट्रक्टर बॉडी के बाहर इंस्टेंस के निर्माण पैरामीटर सुलभ नहीं हैं:
class Baz(val z: String)
// Baz has no other members or methods, so the body may be omitted
val foo = new Foo(4, "ab")
val baz = new Baz("I am a baz")
foo.x // will not compile: x is not a member of Foo
foo.xy // returns "abababab": xy is a member of Foo
baz.z // returns "I am a baz": z is a member of Baz
val bar0 = new Bar
val bar1 = new Bar() // Constructor parentheses are optional here
किसी भी वस्तु के तात्कालिक रूप से त्वरित होने पर किए जाने वाले किसी भी ऑपरेशन को सीधे वर्ग के शरीर में लिखा जाता है:
class DatabaseConnection
(host: String, port: Int, username: String, password: String) {
/* first connect to the DB, or throw an exception */
private val driver = new AwesomeDB.Driver()
driver.connect(host, port, username, password)
def isConnected: Boolean = driver.isConnected
...
}
ध्यान दें कि यह संभव है कि कंस्ट्रक्टर में कुछ दुष्प्रभाव डालें; उपरोक्त कोड के बजाय, किसी को connect
और disconnect
तरीकों पर विचार करना चाहिए ताकि उपभोक्ता कोड IO को शेड्यूल करने के लिए जिम्मेदार हो।
सहायक कंस्ट्रक्टर
एक वर्ग में अतिरिक्त निर्माता हो सकते हैं जिन्हें 'सहायक निर्माता' कहा जाता है। ये रचना में परिभाषाओं द्वारा परिभाषित किए गए हैं जो इसे परिभाषित करते हैं def this(...) = e
, जहाँ e
को किसी अन्य निर्माता को आमंत्रित करना चाहिए:
class Person(val fullName: String) {
def this(firstName: String, lastName: String) = this(s"$firstName $lastName")
}
// usage:
new Person("Grace Hopper").fullName // returns Grace Hopper
new Person("Grace", "Hopper").fullName // returns Grace Hopper
इसका मतलब है कि प्रत्येक निर्माता के पास एक अलग संशोधक हो सकता है: केवल कुछ सार्वजनिक रूप से उपलब्ध हो सकते हैं:
class Person private(val fullName: String) {
def this(firstName: String, lastName: String) = this(s"$firstName $lastName")
}
new Person("Ada Lovelace") // won't compile
new Person("Ada", "Lovelace") // compiles
इस तरह से आप यह नियंत्रित कर सकते हैं कि उपभोक्ता कोड किस तरह से क्लास को इंस्टेंट कर सकता है।