小2C


  • 首页

  • 标签

  • 分类

  • 归档

Java 对象创建的过程

发表于 2019-08-24 | 分类于 Java | 阅读次数:
字数统计: 631 | 阅读时长 ≈ 2

根据符号引用判断是否加载、分配内存(指针碰撞或者空闲链表)、初始化零值、设置对象头(实例是哪个类的实例、类的原位置信息、GC 分代年龄)、调用 方法

对象在内存中的存储布局可以分为个区域:对象头、实例数据、对齐填充(非必需)

对象的定位访问有:句柄和直接指针

具体过程:

  1. 在常量池中查看是否有 new 的参数对应的类的符号引用,并检查这个类是否被加载解析初始化

  2. 加载后,为新对象分配内存,对象所需要的内存大小在类被加载之后就被确定(堆中分配内存:指针碰撞与空闲列表)

  3. 将分配的内存空间初始化为零

  4. 对对象进行必要的设置(元数据,分代年龄等信息)

  5. 执行 <init> 方法,按照程序的值初始化

指针碰撞法:假设 Java 堆中内存是完整的,已分配的内存和空闲内存分别在不同的一侧,通过一个指针作为分界点,需要分配内存时,仅仅需要把指针往空闲的一端移动与对象大小相等的距离

使用的 GC 收集器:serial,parNew

空闲列表法:事实上,Java 堆的内存并不是完整的,已分配的内存和空闲内存相互交错,JVM 通过维护一个列表,记录可用的内存块信息,当分配操作发生时,从列表中找到一个足够大的内存块分配给对象实例,并更新列表上的记录

使用的 GC 收集器:CMS,使用内存不规整的情况下

句柄访问流程如下:

直接访问流程如下:

二者的区别:

这两种对象访问方式各有优势,使用句柄来访问的最大好处就是reference中存储的是最稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要修改。

而使用直接指针访问方式的最大好处就是速度更加快,它节省了一次指针定位的时间开销,由于兑现搞定访问在Java中非常频繁,因此这类开销积少成多后也是一种非常可观的执行成本。

JVM 内存布局

发表于 2019-08-24 | 分类于 Java | 阅读次数:
字数统计: 1.4k | 阅读时长 ≈ 4

JVM 中将内存分为若干部分:堆、方法区、虚拟机栈、本地方法栈、程序计数器

阅读全文 »

Java 中接口和抽象类的区别

发表于 2019-08-24 | 分类于 Java | 阅读次数:
字数统计: 726 | 阅读时长 ≈ 2

抽象类:如果一个类含有抽象方法,则称这个类为抽象类,抽象类必须在类前用 abstract 关键字修饰。抽象方法是一种特殊的方法:他只有声明,而没有具体的实现。所以不能用抽象类创建对象。如果一个类继承抽象类,那么必须为基类中的抽象方法提供定义。如果不这么做,那导出类也为抽象类。

注意,抽象类和普通类的主要区别有以下三点:

  1. 抽象方法必须为 public 或 protected (因为如果为 private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为 public

  2. 抽象类不能用来创建对象

  3. 如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类定义为 abstract 的抽象类

接口:可以含有变量和方法。但是要注意,接口中的变量会被隐式地指定为 public static final 变量(并且只能是 public static final变量,用 private 修饰会报编译错误),而方法会被隐式地指定为 public abstract 方法且只能是 public abstract 方法(用其他关键字,比如 private、protected、static、final 等修饰均会报编译错误),并且接口中所有的方法不能有具体的实现,也就是说,接口中的方法必须都是抽象方法

抽象类和接口的区别:

  1. abstract class 在 Java 语言中表示的是一种继承关系,一个类只能用一次继承关系。但是,一个类却可以实现多个 interface。

  2. 在 abstract class 中可以有自己的数据成员,也可以有非 abstract 的成员方法,而在 interface 中,只能有静态的不能被修饰的数据成员(也就是必须是 static final 的,不过在 interface 中一般不定义数据成员),所有的成员方法都是 abstract 的

  3. 实现抽象类和接口的类必须实现其中的所有方法,如果子类没有实现抽象类的所有抽象方法,那么子类也必须是抽象类;但是子类实现几接口,则必须要把接口的所有抽象方法实现。接口也可以继承接口,此时不需要实现父接口。抽象类中可以有非抽象方法,接口中则不能有非抽象方法。

  4. 接口中定义的变量默认是 public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值

  5. 接口中的方法默认都是 public abstract 型,,也只能是这个类型,不能是 static 方法。static 方法是类方法,他是不允许子类覆写的。因而抽象类可以有 static 方法。

spark 资源调度

发表于 2019-07-16 | 分类于 Spark | 阅读次数:
字数统计: 894 | 阅读时长 ≈ 3

Spark 大数据计算分为两部分,一是资源调度,二是任务调度,可以说这二者贯穿了 Spark 程序运行的始终,因此是十分重要的内容。

阅读全文 »

Spark shuffle

发表于 2019-07-14 | 分类于 Spark | 阅读次数:
字数统计: 2.8k | 阅读时长 ≈ 10

shuffle 指的是数据从 map task 输出到 reduce task 输入的这段过程,shuffle 在 Spark 中主要发生在两个 stage 之间的阶段。 shuffle 是连接 Map 和 Reduce 之间的桥梁,Map 的输出要用到 Reduce 必须要经过 shuffle 这个阶段,shuffle 的性能高低直接影响了整个程序的性能和吞吐量。

阅读全文 »

Spark 广播变量

发表于 2019-07-14 | 分类于 Spark | 阅读次数:
字数统计: 590 | 阅读时长 ≈ 2

本文主要介绍两个内容,一是为什么要使用 Spark 广播变量,二是广播变量的用法。

阅读全文 »

map 和 flatMap 的区别

发表于 2019-07-01 | 分类于 Spark | 阅读次数:
字数统计: 471 | 阅读时长 ≈ 2

flatMap 和 map 都是 对集合内的元素进行操作的函数,两者的区别主要体现在数据类型和返回结果两方面。

阅读全文 »

Spark 算子

发表于 2019-07-01 | 分类于 Spark | 阅读次数:
字数统计: 2.8k | 阅读时长 ≈ 11

spark 的算子操作全都建立在 rdd (弹性分布式数据集) 的基础上,rdd 是一组操作的集合,其内并不包含任何数据,这很好地体现了大数据处理计算移动而数据不动的原则,提供了更高的执行速度。每个 rdd 都包含了以下五个内容

    • A list of partitions
    • A function for computing each split
    • A list of dependencies on other RDDs
    • Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned)
    • Optionally, a list of preferred locations to compute each split on (e.g. block locations for
  • an HDFS file)
阅读全文 »

scala 语法

发表于 2019-06-20 | 分类于 Scala | 阅读次数:
字数统计: 1.8k | 阅读时长 ≈ 7

1.类

scala 的类大致可以分为三种,分别是 class ,object ,trait。

class 就是正常的和其他语言一样类

object 是为了弥补 scala 中没有静态属性而产生的单例类型。若使用 object 定义则不需要 new 也能使用里面的方法和属性,这等于就是将类直接实例化以此来顶替 static

trait 差不多就是一个接口。

具体实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
object demo2 {
//main 方法必须写在 object 类中
def main(args: Array[String]): Unit = {
student("cc",22)

study.show()
val p = new play1
p.show()
}

//形参中的变量必须注明类型,类型在变量后以:(冒号)分隔
def student(name:String,age:Int): Unit ={

println("name:"+name+",age:"+age)

}

}
//单例类,内部方法可以直接调用
object study{

def show(): Unit ={
print("I'm learning")
}
}

trait play{
def show()
}
//感觉和接口没啥区别
class play1 extends play{
override def show(): Unit = {
print("I'm playing")
}
}

2.变量

scala 的变量声明分为 val 和 var 两种,var 声明的是可变变量,val 声明的是不可变变量。scala 的变量类型会自动匹配,所有在声明变量时不需要指定变量类型。如果要指定变量类型,则放在变量后以冒号分隔。

3.函数

scala 的函数有以下特点:

(1)如果没有参数,括号可以省略

(2)如果没有返回值,Unit可以省略,Unit代表没有返回值的函数类型

(3)如果函数内部只有一行代码,则大括号可以省略

(4)如果函数最后一行为返回值,则可以没有 return

(5)函数的返回值类型定义和变量相同,都是放在后面用”:”分隔

(6)利用元组可以做到一次返回多个值,元组元素(a)的提取使用:a._1 为第一个元素,以此类推

具体实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
object demo3 {

def main(args: Array[String]): Unit = {

test1
test2("test2")
println(test3)
var a=test4("test4",1)
println(a._1+","+a._2)

}
//省略小括号
def test1: Unit ={
println("test")
}
//省略大括号
def test2(a:String): Unit = println(a)
//省略 return
def test3:String= "test3"
//返回多个参数
def test4(x:String,y:Int):(String,Int)=(x+"test4",y+1)

}

4.高阶函数

高阶函数指以函数作为参数或返回值的函数,这很好地体现了 scala 面向对象的特点。高阶函数的具体实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
object demo4 {
def main(args: Array[String]): Unit = {


def fun(x: String): String = {
x + "fun"
}
//fun1接受一个函数f,此函数参数为String,返回值也为String

def fun1(f: String => String): String = {
//fun1内部为函数f赋值

var s = f("scala")
s + "fun1"
}

def fun2(f: String): String = f + "fun2"

//任何参数为String,返回值为String的函数都可以作为fun1的函数
val a = fun1(fun)
println(a)
//首先将函数fun2传入fun1进行赋值操作,之后将结果传入fun函数进行操作

println(fun(fun1(fun2)))

}
}

对比上述语句可以发现=>的作用是指定作为参数的函数输入值类型和函数的返回值的类型。当函数作为参数传递时,传递目标是高级函数则传递的是函数,若传递目标是一般函数则传递的是函数的返回值

5.匿名函数

形如 (x:String)=>x+"demo" 的就是匿名函数,匿名函数可以用来直接给高阶函数传参。

1
2
3
4
5
6
7
8
//fun1接受一个函数f,此函数参数为String,返回值也为String
def fun1(f: String => String): String = {
//fun1内部为函数f赋值
var s = f("scala")
s + "fun1"
}
fun1(x=>x+"匿名函数")
运行结果为:scala匿名函数fun1

如果匿名函数是作为一个变量传递时需要指定匿名函数内变量类型,如果是直接用来处理数据的则可以不指定数据类型。

6.foreach

使用 foreach 来进行遍历操作,示例如下:

1
2
3
4
5
6
7
8
9
10
val list = List(1,2,3,4,5)
//对数据进行操作,不需要指定变量类型

list.foreach(x=>println(x))
//这里"_"代指遍历时的每个元素

list.foreach(println(_))
//这个好像是 println 函数的特殊性有关,没看源码搞不清

list.foreach(println)

7.reduce

reduce 是一个聚合函数,用于对集合中的数据进行处理,reduce包含reduceLeft和reduceRight,reduce默认使用reduceLeft。所谓聚合就是将集合中的元素按照一定的顺序依次相加。具体示例如下:

1
2
3
val list = List(1,2,3,4,5)
println(list.reduce(_+_))
显示结果为:15

8.<- (for循环)

此符号在 Scala 中主要放在循环语句中,用于将集合中的元素映射到变量中,类似于 python 中的 in 。示例如下:

1
2
3
4
5
6
7
//单元素循环
for (x<- 1 to 10)
println(x)
//多元素循环
for (x <- 1 to 6; y <- 1 to 6) {
println(x, y)
}

9.列表操作

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//创建列表
val list = List(1,2,3,4,5,6)
//遍历列表
//1.foreach 无返回值
list.foreach(x=>println(x*2))
//2.map 有返回值
list = list.map(x=>x*2)
println(list)
//获取列表长度
lenth=list.length
//截取列表
//1.保留列表前两位
list1 = list.take(2)
//2.删除列表前两位
list2 = =list.drop(2)
//反转列表
list3 = list.reverse
//将列表内的元素以指定字符串分割转换成字符串
str = list.mkString(",")
//将字符串转化成列表
list4 = str.split(",").toList

9.1 列表添加元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//由于 scala 中的 List 添加元素是地址添加而不是值添加,因此每次添加都需要重新创建对象,效率不高,
//因此选择使用 ListBuffer 来进行元素添加操作,添加后再将 ListBuffer 转成 List
val lb = new ListBuffer[Int]
//插入一个元素
lb.+=(1)
//插入多个元素
lb.++=(List(2,3,4,5,6))
//从前面插入元素
lb.+=:(7)
//从后面插入元素
lb.+=(0)
//插入到指定位置,第一个参数为插入位置
lb.insert(0,0)
//删除元素,删掉两个0的其中一个
lb.-=(0)
//将ListBuffer转成List
lb.toList

10.map集合

map 集合是存储键值对的数据类型,用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//变量赋值
val map = Map("java"->"scala","hadoop"->"Hive","Python"->"Scripy")
//根据 key 获取 value
val v = map.get("java") //此处得到的是一个 Option 对象
val a = v.get //此处得到 Option 对象内的值,也就是说根据 key 获取 value需要经过两次处理
//使用上述语句来查找 value 时可能会出现空指针异常,为此可以使用 getOrElse 方法
//该方法根据 key 查找对应 value,若 value 存在则返回 value,若不存在则返回默认值
val b = map.getOrElse("java","默认值")
//遍历 map
map.foreach(kv=>{
val k=kv._1
val v=kv._2
println(s"key:$k,value+$v")
})

11.match 模式匹配

match 和 java 中的 witch 差不多,多用在 map 操作中,防止空指针异常。具体用法如下:

1
2
3
4
5
6
7
8
val map = Map("java"->"scala","hadoop"->"Hive","Python"->"Scripy")

val a = map.get("java1") match {
case b:Some[String]=>b.get//如果元素存在则取出值

case None => "默认值"//如果元素不存在则返回默认值

}//此处相当于 getOrElse

sqoop 操作

发表于 2019-06-10 | 阅读次数:
字数统计: 1.2k | 阅读时长 ≈ 4

Sqoop是一个用来将Hadoop和关系型数据库中的数据相互转移的工具,可以将一个关系型数据库(例如 : MySQL ,Oracle ,Postgres等)中的数据导进到Hadoop的HDFS中,也可以将HDFS的数据导进到关系型数据库中。

阅读全文 »
1…678
or

or

未来的全栈工程师

79 日志
9 分类
6 标签
© 2021 or
历史访客数: 总访问量:
0%