1.关于类的构造
abstract class RDD[T: ClassTag](
@transient private var _sc: SparkContext,
@transient private var deps: Seq[Dependency[_]]
) extends Serializable with Logging {
1.类名后面直接有括号,括号里面的成员从理论上讲,都是这个类的成员
2.在类构造的时候,必须传入的参数
这个构造器叫主构造器,当然构造器可以重载
/** Construct an RDD with just a one-to-one dependency on one parent */
def this(@transient oneParent: RDD[_]) =
this(oneParent.context , List(new OneToOneDependency(oneParent)))
但是可以见到,重载的构造器也是一定直接或者间接地去调用了主构造器
class SparkContext(config: SparkConf) extends Logging with ExecutorAllocationClient
def this() = this(new SparkConf())
def this(config: SparkConf, preferredNodeLocationData: Map[String, Set[SplitInfo]]) = {
this(config)
logWarning("Passing in preferred locations has no effect at all, see SPARK-8949")
}
def this(master: String, appName: String, conf: SparkConf) =
this(SparkContext.updatedConf(conf, master, appName))
//以下的重在构造器是间接调用主构造器
private[spark] def this(master: String, appName: String) =
this(master, appName, null, Nil, Map())
所以重载构造器要么直接调用主构造器,要么间接调用主构造器
2.在类的代码中,那些不被方法封装的代码,什么时候会被执行实例化的呢?
其实就是在主构造器调用的时候,它会实例化很多全局的变量,而且还能强制让你做一些事情(很多框架都会做这件事情)
那是不是说类的所有成员,在类被实例化的时候,就必须实例化呢?
有些成员是,后面会用到,但是不需要在启动的时候用到
这时候,scala出现另外一个语法现象:lazy!!!!
lazy val listenerManager: ExecutionListenerManager = new ExecutionListenerManager
protected[sql] lazy val catalog: Catalog = new SimpleCatalog(conf)
@transient
protected[sql] lazy val functionRegistry: FunctionRegistry = FunctionRegistry.builtin.copy()
@transient
protected[sql] lazy val analyzer: Analyzer =
new Analyzer(catalog, functionRegistry, conf) {
override val extendedResolutionRules =
ExtractPythonUDFs ::
PreInsertCastAndRename ::
(if (conf.runSQLOnFile) new ResolveDataSource(self) :: Nil else Nil)
override val extendedCheckRules = Seq(
datasources.PreWriteCheck(catalog)
)
}
@transient
protected[sql] lazy val optimizer: Optimizer = DefaultOptimizer
这些都是在第一次使用的时候才进行实例化!!!例如,这里就是需要解析SQL的时候,这些实例才会用到,如果不写语句,就用不到
3.object就相当于class的唯一的静态的单例,Scala没有static关键字,使用object作为全局唯一的实例,一般情况下,都会复写apply方法
当全局只能有一个唯一的实例的时候,我们一般不会复写apply方法
一般,想要构造很多实例的时候,都会复写apply方法
object RDD {
// The following implicit functions were in SparkContext before 1.3 and users had to
// `import SparkContext._` to enable them. Now we move them here to make the compiler find
// them automatically. However, we still keep the old functions in SparkContext for backward
// compatibility and forward to the following functions directly.
implicit def rddToPairRDDFunctions[K, V](rdd: RDD[(K, V)])
(implicit kt: ClassTag[K], vt: ClassTag[V], ord: Ordering[K] = null): PairRDDFunctions[K, V] = {
new PairRDDFunctions(rdd)
}
implicit def rddToAsyncRDDActions[T: ClassTag](rdd: RDD[T]): AsyncRDDActions[T] = {
new AsyncRDDActions(rdd)
}
implicit def rddToSequenceFileRDDFunctions[K, V](rdd: RDD[(K, V)])
(implicit kt: ClassTag[K], vt: ClassTag[V],
keyWritableFactory: WritableFactory[K],
valueWritableFactory: WritableFactory[V])
: SequenceFileRDDFunctions[K, V] = {
implicit val keyConverter = keyWritableFactory.convert
implicit val valueConverter = valueWritableFactory.convert
new SequenceFileRDDFunctions(rdd,
keyWritableFactory.writableClass(kt), valueWritableFactory.writableClass(vt))
}
implicit def rddToOrderedRDDFunctions[K : Ordering : ClassTag, V: ClassTag](rdd: RDD[(K, V)])
: OrderedRDDFunctions[K, V, (K, V)] = {
new OrderedRDDFunctions[K, V, (K, V)](rdd)
}
implicit def doubleRDDToDoubleRDDFunctions(rdd: RDD[Double]): DoubleRDDFunctions = {
new DoubleRDDFunctions(rdd)
}
implicit def numericRDDToDoubleRDDFunctions[T](rdd: RDD[T])(implicit num: Numeric[T])
: DoubleRDDFunctions = {
new DoubleRDDFunctions(rdd.map(x => num.toDouble(x)))
}
}
object中的方法是所有的实例都能使用的
class可以访问object的一切内容,即使是private的
class和object必须写在同一个文件中
为什么很多人写框架的时候都用伴生对象?
除了1.节省空间
2.全局
3.唯一
4.工厂方法
5.隐式转换
海油6.虽然class可以直接调用object中的成员,但是object并不是class的接口一部分,所以会把很多实验性的api放到object中
归纳总结:1.看类的构造的笔记
2.在类的代码中,那些不被方法封装的代码,什么时候会被执行实例化的呢?这样做的好处是什么?那是不是说类的所有成员,在类被实例化的时候,就必须实例化呢?
3.再次思考object与class的。为什么很多人写框架的时候都用伴生对象?