《财富自由之路》笔记

## 1.你知道自己未来的样子吗?

如果你笃信自己的未来是那样一条曲线,那么在成本线被突破之前那段长长的时间里,你能赚到的钱实际上全部是“小钱”,小到“不值得节省”的地步,就算要省,也省不出多少。

## 2.你知道那条曲线究竟是什么吗?
只要是能积累的东西,大都会产生复利效应。在智力上、知识上、经验上,复利效应对每个人来说都是存在的。仔细观察一下每个人的成长过程就能明白,从出生开始,所有人都不断习得各种技能,不断积累,只不过很多人在20岁以后就停止学习,所以没有机会在自己的未来体会到复利效益。早晚有一天终生成长者会跨过那个拐点(也就是里程碑),然后扬长而去,这就是复利效益的威力。

## 3.究竟什么是财富自由?
所谓“个人财富自由”,是指某个人再也不用为了满足生活必需而出售自己的时间了。
财富自由根本不是终点站,那只是一座里程碑,在那之后还有很长的路要走。

## 4.起步时最重要的是什么?
快速入门不仅绝对有可能,而且绝对必要。
在学习任何一个学科的知识时,都有一个很重要的概念:最少必要知识。当需要获得某项技能的时候,一定要想办法在最短的时间里弄清楚都有哪些最少必要知识,然后迅速掌握它们。如果掌握了这些知识,你就已经入门了,接下来只剩所谓“执行”,一个字——用。

学习能力也好,执行力也罢,核心只有一个:在刚开始的时候,平静地接受自己的笨拙。接受自己的笨拙,理解自己的笨拙,放慢速度尝试,观察哪里可以改进,反复练习,观察哪里可以进一步改进,进一步反复练习….这是学习一切技能的必需过程,关键在于:

  • 尽快开始这个过程
  • 尽快度过这个过程

## 5.你认真考虑过自己的商业模式吗?
所谓个人商业模式,就是一个人出售自己时间的方式。
仔细看看个人的商业模式的基本分类:

  • 第一种:一份时间只出售一次(零工或者上班)
  • 第二种:同一份时间出售很多次(作者)
  • 第三种:购买他人的时间再卖出去(创业和投资)

笼统的看,对个体而言,所谓进步,就是逐步学会并使用各种个人商业模式,然后想办法优化属于自己的商业模式。

## 6.如何优化第一种个人商业模式?

《从点子到产品》 学习笔记与读后感

读后感

读罢本书,如果作为一个不是产品经理岗位的人员,也可以了解一个产品从构思到最终上线,到上线后的反馈,都是一个异常繁琐的过程,是有一定的生命周期的。生命周期这个词用的甚好,意味着从一个点子到最终诞生称为一个产品,中间的过程实际上是有很多的挫折,就如同人的成长过程一样,总会越到各式各样的困难(需要抉择、需要解决的需求)。本书着重强调的是产品经理工作当中的思维方式,方法论,工作的流程,包含自我的成长,驱动力等,并非是一般的有关于产品经理工具之类的书籍,直接教你怎么制作原型,哪几种收集数据的方式,注意一些沟通技巧等,实际上每个产品所面临的问题和环境都不一样,那么我们其实需要的远远不是一个工具,更多的是面临工作环境需要时候的,分析,寻找问题,解决问题的思维方式,提升工作的处理、解决问题的能力。这一点上,本书会给对从事产品经理岗位的人直接的帮助。感兴趣的朋友也可以关注作者在知乎的相关作品(https://www.zhihu.com/pub/book/119553546)。

除了对于了解产品经理做什么有所帮助之外,作者本身对于互联网产品的看法和观点,也是值得相关领域的从业者去思考的。从产品角度作者都深度参与过像锤子手机、嘟嘟美甲O2O(现已倒闭),点我达外卖配送的产品。作者把工作期间一些典型的问题作为案例,表述的浅显易懂,还是值得学习的,换做我是一个开发工程师,也能够理解当一个需求,从产品经理手中经过的时候,实际上经历了多少流程,最终再落实到具体的研发过程中。

总之,好的产品经理会给一个产品和团队注入诸如灵魂之类的事情,反之,可能让开发、市场“白忙活”一场,变向的打击人员的士气,恶性循环,内部人员之间彼此不信任,矛盾丛丛,工作更是无从良性开展合作,也就离死不远了。

本书主要观点如下

## 第一部分 产品价值和用户痛点
### 点子与方案
– 点子落地之前,务必先“纸上谈兵”一回
– 说服身边最理性的人和最吹毛求疵的人认可你的想法
– 证明你们的团队可靠,跟证明方案本身的可靠同样重要

### 找到产品核心价值
– 解决不了问题的产品,只能靠补贴和红包留住用户。一旦遇到更大的红包,用户说走就走
– 问题解决得够彻底,下次用户会主动来找你

### MVP与痛点
– 大部分在等待功能完善、交互完美、界面出色才能一炮而红的产品,往往都没有等到那一天
– 产品初期做设计要多做减法
– 初期把整体流程跑通时不用特别在意是不是用“互联网方式”

## 第二部分 需求分析和功能设计
### 深挖需求
– 区分用户表达的究竟是诉求,还是具体的方案
– 不断假想自己是用户,以及真正到用户场景下体验都是发掘需求本质的好方法

### 用户研究
– 做可量化的研究,要警惕数据陷阱
– 做可定性的研究,要发掘背后的原委
– 最好的用研,就是自己成为客户

### 用户体验
– 任何你觉得可能会“不太舒服”的地方,在市场上很可能会让成千上万的用户“很不舒服”
– 任何你觉得已经够完善的方案,仍然会有优化的空间

## 第三部分 产品管理
### 文档管理
– 了解技术是为了更好地设计功能和协作,并不是帮技术的同事完成工作
– 不管文档是什么形式、篇幅如何,能让开发人员们看得懂的就是好文档
– 文档的完整性、逻辑性比文档的可读性』美观程度都重要

### 需求管理
– 每个需求为什么在目前的位置和状态,产品经理应当了如指掌
– 需求的各种变化、调整和意外,应该同步到整个团队中
– 工具:如四象限法则。

### 工作流中的管理
– 好的产品经理不仅要自己有执行力,还应推动团队提升执行力
– 要始终避免浪费生命在无意义的劳动上
– 出现了任何问题,避免以后再犯跟解决当下的问题同样重要

## 第四部分 技巧和方法
### 处理问题
– 不仅能解决问题,还要对未解决的问题也心里有数
– 对团队来说,最有价值的产品经理应该能像打地鼠一样去清除问题

### 沟通
– 会沟通不等同于能讨人喜欢或者伶牙俐齿,沟通需要后天的“修行”
– 最高阶的沟通是要让别人促进自己的工作

### 成长
– 有一个导师的指导,比看书和资料有帮助很多
– 少读快餐式的文章
– 要学会把自己的知识点和资料结构化整理
– 要把自己也当成产品去迭代升级

### 兴趣和热情
– 工作中的受挫和茫然,通常都是新的成长的开始
– 跟优秀的人共事,也是吸收正能量的方法

#大数据学习笔记第7天# 面向对象1

回顾


二维数组

元素本身是一维数组的数组。

三种初始化方式:
1) int[][] arr = new int[2][];
2) int[][] arr = new int[2][2];
3) int[][] arr = new int[][]{{1,2}, {3,4,5}}; // 简化写法见第4种
4) 简化写法省略掉公共的部分:int[][] arr = {{1,2}, {3,4,5}};

作业

自定义Laptop类,做好封装,并测试。
*E:\01\01 Java\day07\code\Laptop.java*

Select Code
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
36
37
38
39
40
41
42
43
/*
自定义类
*/
class Laptop{
	//成员属性
	private String brand;
	private int price;
	
	//封装方法
	public void setBrand(String brand){
		this.brand = brand;
	}
	
	public String getBrand(){
		return brand;
	}
	
	public void setPrice(int price){
		this.price = price;
	}
	
	public int getPrice(){
		return price;
	}
		
	//构造函数
	public Laptop(){}
	public Laptop(String brand){
		this.brand = brand;
	}
	public Laptop(int price){
		this.price = price;
	}
	public Laptop(String brand, int price){
		this(brand);
		this.price = price;
	}
	
	//成员方法
	public void show(){
		System.out.println("Brand:" + brand + ", Price:" + price);
	}
}

*E:\01\01 Java\day07\code\LaptopDemo.java*

Select Code
1
2
3
4
5
6
7
8
9
/*
测试类
*/
public class LaptopDemo{
	public static void main(String[] args){
		Laptop pc = new Laptop("Dell", 3500);
		pc.show();
	}
}

效果如图:

大纲


### 第一节课
– 面向对象编程思想
– 类的定义
– 对象的初始化
– 成员变量
– 自定义长方形类
– 自定义员工类
– 自定义计算类

### 第二节课
– static关键字
– main方法传参
– 工具类的制作
– API文档的使用
– 代码块

### 第三节课
– 继承
– 子类使用变量的原则
– super关键字
– 方法重写与子类对象实例化
– final关键字

### 第四节课
– 抽象类
– 抽象方法
– 接口


面向对象编程思想

### 1. 理解面向对象
– 面向对象是相对面向过程而言
– 面向对象和面向过程都是一种思想
– 面向对象是基于面向过程的

### 举例
– 电脑组装
– 建造汽车
– 泡咖啡
– 使用JDK的Scanner类

### 2. 面向对象的特点
– 是一种符合人们思考习惯的思想
– 可以将复杂的事情简单化
– 将程序员从执行者转换成指挥者
– 完成需求时:
– 先要去找具有所需的功能的对象来用
– 如果该对象不存在,那么创建一个具有所需功能的对象
– 简化开发并提高复用

### 3. 面向对象开发、设计、特征
– 开发的过程:其实就是不断的创建对象,使用对象,指挥对象做事情;
– 设计的过程:其实就是在管理和维护对象之间的关系;
– 面向对象的特征:
– 封装
– 继承
– 多态

### 3.2 类与对象的关系
– 使用计算机语言就是不断的在描述现实生活中的事物
– java中描述事物通过类的形式体现,类是具体事物的抽象,概念上的定义
– 对象(实例)即是该类事物实实在在的个体
– 万物皆对象

### 什么是类?
可以理解为:
– 类就是从对象中抽象出来的共性;
– 具体学生对象就是实实在在的个体;
– 一个类可以创建多个对象;

### 实例:Dog类

定义一个类主要是两方面内容:成员变量(事物的属性)、成员方法(事物的行为)。

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
定义一个Dog类:
成员属性:事物的属性
成员方法:事物的行为
*/
public class Dog{
	// 成员属性:名字、年纪、性别
	String name="wancai";
	int age=2;
	int sex=0;
	
	// 成员方法:吃、喝、叫
	public void eat(String food){
		System.out.println("正在吃:"+food);
	}
}

类的定义

– 生活中描述事物无非就是描述事物的属性和行为。如:狗有颜色和年龄等属性,有跑和叫等行为。
– Java中用类Class来描述事物也是如此:
– 事物的属性:对应类中的成员属性
– 事物的行为:对应类中的成员方法
– 定义一个类,其实就是定义类中的成员(也就是成员属性和成员方法)

类成员的写法

– 成员变量:
– 和之前定义变量的规则是一致的
– 写在类中,成员方法的外面
– 成员方法:
– 和之前定义的方法一样
– 暂时去掉static

代码实例:

*E:\01\01 Java\day07\code\Car.java*

Select Code
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
/*
自定义类:从具体事物到抽象概念的过程。
自定义Car类:
	- 成员变量:对应的是事物的属性
	- 成员方法:对应的是事物的行为(功能)
成员变量有默认值

类是一个抽象的概念,具体使用的是创建的实例(对象)。
如何从一个类创建出对象呢?
	创建对象 Scanner s = new Scanner(System.in)
	类型名 对象名 = new 类型名()
	
	Car car = new car();
*/

public class Car{
	String brand;
	String color;
	int age;
	
	public void run(){
		System.out.println("the car is running");
	}
	
	public void load(){
		System.out.println("the car can load people");
	}
}

*E:\01\01 Java\day07\code\CarDemo.java*

Select Code
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
/*
演示Car类如何创建对象

成员变量:
	赋值
	访问
成员方法:
	访问
	
JDK里非java.lang下的包才需要手动导入。

Scanner, Math都不需要手动导入。
*/
public class CarDemo{
	public static void main(String[] args){
		Car car=new Car();
	
		//对成员属性进行赋值
		car.brand="BMW";
		car.color="White";
		car.age=2;
		
		//对成员属性进行访问
		System.out.println(car.brand);	//默认值是null
		System.out.println(car.color);	//默认值是null
		System.out.println(car.age);	//默认值是0
		
		//访问成员方法
		car.run();
		car.load();
	}
}

作业:自定义一个Laptop类。
*E:\01\01 Java\day07\code\Laptop2.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
自定义Laptop类
	成员变量:
		品牌
		尺寸
		价格
	成员方法:
		放电影
		放音乐
*/
public class Laptop2{
	//成员变量
	String brand;
	double size;
	int price;
	
	//成员方法
	public void playMovie(String name){
		System.out.println("正在播放电影:" + name);
	}
	public void playMusic(String name){
		System.out.println("正在播放音乐:" + name);
	}
}

*E:\01\01 Java\day07\code\Laptop2Demo.java*

Select Code
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
/*
Laptop类测试
*/
public class Laptop2Demo{
	public static void main(String[] args){
		Laptop2 pc1 = new Laptop2();
		//对成员变量赋值
		pc1.brand="联想";
		pc1.size=15.6;
		pc1.price=5000;
		//成员方法调用
		System.out.println(pc1.brand);
		System.out.println(pc1.size);
		System.out.println(pc1.price);
		
		Laptop2 pc2 = new Laptop2();
		//对成员变量赋值
		pc2.brand="DELL";
		pc2.size=18.6;
		pc2.price=6000;
		//成员方法调用
		System.out.println(pc2.brand);
		System.out.println(pc2.size);
		System.out.println(pc2.price);
		
		//创建自定义类型的变量,指向已经存在的对象
		Laptop2 pc3 = pc1;
		//成员方法调用
		System.out.println(pc3.brand);
		System.out.println(pc3.size);
		System.out.println(pc3.price);
	}
}

效果如图:

成员变量和局部变量的区别

– 成员变量
– 成员变量定义在类中,作用范围是整个类
– 实例变量随着对象的创建而存在,随着对象而消失
– 存在于对象所在的”堆内存”中
– 成员变量有默认初始化值(0,0.0,false,null)
– 局部变量
– 局部变量定义在局部范围内:方法内、形参上、代码块内
– 局部变量存在于”栈内存”中
– 方法或者语句执行完,变量空间自动释放
– 局部变量没有默认初始值,除了形参,使用之前必须赋值

### 对象内存图

形式参数的问题

Java中参数传递的原则:值传递
– 基本数据类型
– 数组
– 自定义类

举例形参是一个对象的例子:
*E:\01\01 Java\day07\code\Student.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
/*
自定义Student类
*/
public class Student{
	String name;
	int age;
	String sex;
	
	public void study(){
		System.out.println("正在学习");
	}
}

*E:\01\01 Java\day07\code\StudentTest.java*

Select Code
1
2
3
4
5
6
7
8
9
10
/*
此类用于对Student的实例进行测试
调用实例的一个方法
*/
public class StudentTest{
	public void test(Student s){
		//调用形参对象的方法
		s.study();
	}
}

*E:\01\01 Java\day07\code\StudentDemo.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
/*
对形参是自定义类型的方法进行测试
*/
public class StudentDemo{
	public static void main(String[] args){
		//创建测试类的对象
		StudentTest st = new StudentTest();
		//创建学生对象,当成参数传给test方法
		Student s = new Student();
		//调用test方法
		st.test(s);
	}
}

效果如图:

匿名对象

匿名对象是对象的简写形式。

例子:
new StudentTest().test(new Student());

匿名对象两种使用情况:
– 对象方法仅进行一次调用时,多次调用不适合
– 匿名对象可以作为实际参数进行传递

使用匿名对象的好处:
– 简化写法,不必定义变量接住对象引用
– 对象用完之后就编程垃圾内存,可以被垃圾回收器回收(一个对象,只要有变量指向它,就不能被垃圾回收器回收)

封装

封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式,面向对象的三大特点之一,其余两个:继承和多态。

好处:
– 防止数据被任意篡改,提高安全性
– 隐藏了实现细节,仅暴露方法

如何实现封装:
– 使用private关键字修饰成员变量
– 对外提供公有的setter和getter方法

private关键字:
– 是一个权限修饰符
– 用于修饰成员(成员变量和成员方法)
– 被私有化的成员只能在本类中直接访问

常见方法:
– 将成员变量设为私有,这样就防止在类外进行访问,对外提供相应的公有的setxxx和getxxx方法
– 好处是提高对数据访问的安全性,并且可以增加复杂的逻辑控制

封装前,可以给对象的属性直接进行赋值操作,如图:

封装后,访问私有变量会直接报错,如图

代码实例:
*E:\01\01 Java\day07\code\Person.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
自定义Person类
*/
public class Person{
	//使用关键字private进行封装
	private String name;
	private int age;
	
	//定义setter方法和getter方法
	public void setName(String n){
		name = n;
	}
	public String getName(){
		return name;
	}
	
	public void setAge(int m){
		age = m;
	}
	public int getAge(){
		return age;
	}
}

*E:\01\01 Java\day07\code\PersonDemo.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
测试Person类
*/
public class PersonDemo{
	public static void main(String[] args){
		Person p = new Person();
		//p.name="张三";
		//p.age=200;
		//System.out.println(p.name);
		//System.out.println(p.age);
		
		p.setName("李四");
		p.setAge(80);
		System.out.println(p.getName());
		System.out.println(p.getAge());
	}
}

this关键字

作用:this代表当前正在调用的方法对象。

使用场景:
– setXxx方法中对成员变量赋值,区分成员变量和局部变量
– 构造方法互相调用:this(…); 注意:构造方法中使用this或者super调用其他构造方法必须是构造方法中的第一条语句。
– 方法中调用本类其他方法

代码实例:
*E:\01\01 Java\day07\code\ThisDemo.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
this关键字:用来区分局部变量和成员变量。使用this引用的就是成员变量。
*/
class Demo{
	private int age;
	public void setAge(int age){
		//根据究竟原则,此时的age,都是取的局部变量,没有从参数传递过来的age
		//age = age;
		this.age = age;
	}
	public int getAge(){
		return age;
	}
}

public class ThisDemo{
	public static void main(String[] args){
		Demo d = new Demo();
		d.setAge(100);
		System.out.println(d.getAge());	//0
	}
}

构造方法

特点:
– 构造方法是一种特殊的方法,它的方法名和类名相同
– 不用定义返回值类型,不用return关键字
– 其返回值可以理解为是新创建对象的引用,不用显式定义

作用:给对象初始化,即给成员变量赋值。

注意:
如果没有写,系统提供一个默认(空参)构造方法,一旦定义了构造方法就不会,系统不会提供任何构造方法
– 多个构造方法是以重载的形式存在的
– 使用new Student();实际上就是在调用空参构造方法

代码实例:

Select Code
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
36
/*
构造方法实例
*/
class People{
	private int age;
	public void setAge(int age){
		this.age=age;
	}
	public int getAge(){
		return age;
	}
	
	//定义无参构造方法
	public People(){
		System.out.println("访问了无参构造方法");
	}
	//定义有参构造方法,利用了方法重载
	public People(int age){
		System.out.println("访问了有参构造方法");
		this.age=age;
	}
	
	public void show(){
		System.out.println("当前年龄是:" + age);
	}
}

public class PeopleDemo{
	public static void main(String[] args){
		People p1 = new People();
		p1.show();
		
		People p2 = new People(10);
		p2.show();
	}
}

如图:

一个标准类的定义和使用

以Student类为例,定义标准的javabean
成员变量:自己分析,用私有修饰
成员方法:
– 空参构造方法
– 普通成员方法
– get/set方法
如果不希望单独获取成员变量的值,可以不定义setXxx方法
给成员变量赋值的方式有两种:set方法和构造方法

代码实例:
*E:\01\01 Java\day07\code\NoteBook.java*

Select Code
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/*
定义一个标准类:
	1.私有的成员属性
	2.公有的set/get方法
	3.空参构造方法
*/
public class NoteBook{
	private String brand;
	private int price;
	private double size;
	
	public void setBrand(String brand){
		this.brand=brand;
	}
	public String getBrand(){
		return brand;
	}
	public void setPrice(int price){
		this.price=price;
	}
	public int getPrice(){
		return price;
	}
	public void setSize(double size){
		this.size=size;
	}
	public double getSize(){
		return size;
	}
	
	//空参构造
	public NoteBook(){
		
	}
	//带参构造函数
	public NoteBook(String brand, int price, double size){
		this.brand=brand;
		this.price=price;
		this.size=size;
	}
	
	public void playMusic(){
		System.out.println("正在播放音乐");
	}
	
	public void show(){
		System.out.println(brand + "," + price + "," + size);
	}
}

*E:\01\01 Java\day07\code\NoteBookDemo.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
NoteBook测试类
*/
public class NoteBookDemo{
	public static void main(String[] args){
		//访问空参构造方法
		NoteBook book1 = new NoteBook();
		book1.setBrand("Dell");
		book1.setPrice(3500);
		book1.setSize(16.8);
		book1.show();
		book1.playMusic();
		
		//访问带参构造方法
		NoteBook book2 = new NoteBook("Lenovo", 5800, 24.8);
		book2.show();
		book2.playMusic();
	}
}

效果显示:

this关键字在构造方法中的使用:

– 在某个构造方法中调用本类的其他构造方法
– 必须放在构造方法的第一句

代码实例:

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
public NoteBook(String brand, int price, double size){
	this(brand, price);
	this.size=size;
}

//this关键字的使用
public NoteBook(String brand, int price){
	this(price);
	this.brand=brand;
}
public NoteBook(int price){
	this.price=price;
}

一个对象的完整实例化过程

以Student s=new Student();为例

– 加载Student.class文件到方法区;
– 在栈内存中定义变量s;
– 在堆内存中开辟空间;
– 对成员变量进行默认初始化(0,0.0,false,null)
– 对成员变量进行显式初始化(定义成员变量时赋值)
– 调用构造方法(成员变量赋值)
– 成员变量初始化完毕,将对象地址值返回给栈中的变量s

### 练习
什么时候将变量定义为成员变量?
变量是用来描述类的,如果变量是这个类的描述信息,就定义为成员变量,否则,应该定义为方法形参或者方法体内,即:局部变量。

变量定义的原则:范围越小越好,能够被及时回收。

练习题:
1. 定义长方形类,其中包含求周长(perimeter)和面积(area)的方法。注意:由于没有必要单独获取长和宽,所以不需要定义get方法。
2. 定义员工类,自己分析有什么成员变量,包含一个显示所有成员变量的方法,然后测试。
3. 自定义计算类,提供基本的加减乘除运算,并测试。被计算的数和类之间没有从属关系,最好不要定义成员变量,而是方法的参数。

例1:

*E:\01\01 Java\day07\code\Rectangle.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
自定义长方形类
*/
public class Rectangle{
	private int length;
	private int width;
	
	public void setLength(int length){
		this.length=length;
	}
	public void setWidth(int width){
		this.width=width;
	}
	
	public int getPerimeter(){
		return 2*(length+width);
	}
	public int getArea(){
		return length * width;
	}
}

*E:\01\01 Java\day07\code\RectangleDemo.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
测试长方形类
*/
import java.util.Scanner;

public class RectangleDemo{
	public static void main(String[] args){
		Rectangle r = new Rectangle();
		Scanner s = new Scanner(System.in);
		
		System.out.println("请输入长方形的长度:");
		r.setLength(s.nextInt());
		System.out.println("请输入长方形的宽度:");
		r.setWidth(s.nextInt());
		
		System.out.println("周长:"+r.getPerimeter());
		System.out.println("面积:"+r.getArea());
		
	}
}

例2:

*E:\01\01 Java\day07\code\Employee.java*

Select Code
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
36
37
38
/*
自定义员工类
*/
public class Employee{
	private String name;
	private String dept;
	private int age;
	
	public void setName(String name){
		this.name = name;
	}
	public String getName(){
		return name;
	}
	public void setDept(String dept){
		this.dept = dept;
	}
	public String getDept(){
		return dept;
	}
	public void setAge(int age){
		this.age = age;
	}
	public int getAge(){
		return age;
	}
	
	public Employee(){}
	public Employee(String name, String dept, int age){
		this.name=name;
		this.dept=dept;
		this.age=age;
	}
	
	public void show(){
		System.out.println(name + ", " + dept + ", " + age);
	}
}

*E:\01\01 Java\day07\code\EmployeeDemo.java*

Select Code
1
2
3
4
5
6
7
8
9
/*
测试员工类
*/
public class EmployeeDemo{
	public static void main(String[] args){
		Employee e = new Employee("Leon", "IT", 31);
		e.show();
	}
}

例3:

*E:\01\01 Java\day07\code\Calc.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
自定义两个数用于加减乘除
*/
public class Calc{
	private int num1;
	private int num2;
	
	public Calc(){}
	
	public int add(int num1, int num2){
		return num1+num2;
	}
	public int sub(int num1, int num2){
		return num1-num2;
	}
	public int mul(int num1, int num2){
		return num1*num2;
	}
	public double div(int num1, int num2){
		return num1/num2;
	}
}

*E:\01\01 Java\day07\code\CalcDemo.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
用于计算类的测试用例
*/
import java.util.Scanner;

public class CalcDemo{
	public static void main(String[] args){
		Calc c = new Calc();
		Scanner s=new Scanner(System.in);
		int num1;
		int num2;
		
		System.out.println("请输入第1个数:");
		num1 = s.nextInt();
		System.out.println("请输入第2个数:");
		num2 = s.nextInt();
		
		System.out.println("加:" + c.add(num1, num2));
		System.out.println("减:" + c.sub(num1, num2));
		System.out.println("乘:" + c.mul(num1, num2));
		System.out.println("除:" + c.div(num1, num2));
	}
}

## static关键字
用于修饰成员(成员变量和成员方法),称为类成员。

代码实例:

*E:\01\01 Java\day07\code\StaticTest.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
/*
演示static关键字
*/
public class StaticTest{
	//修饰类成员属性
	static int age;
	
	//修饰类成员方法
	public static void show(){
		System.out.println("Hello");
	}
}

*E:\01\01 Java\day07\code\StaticDemo.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
测试Staic修饰关键字的使用
*/
public class StaticDemo{
	public static void main(String[] args){
		//使用类名直接访问类成员
		StaticTest.age=10;
		System.out.println(StaticTest.age);
		StaticTest.show();
		
		//使用对象来访问类成员
		StaticTest st = new StaticTest();
		st.age=20;
		System.out.println(st.age);
		st.show();
	}
}

总结:静态方法不能访问非静态成员;非静态方法则可以访问静态成员。(原因是先有静态成员)

被修饰后的类成员有如下特点:
– 随着类的加载而加载
– 优先于对象而存在
– 被这个类的所有对象共享
– 可以直接被类名调用,也可以使用对象调用,但推荐使用类名调用,因为static修饰的成员就是类成员

使用时注意:
– 静态方法只能访问静态成员(变量,方法)
– 静态方法中不可以使用this, super关键字
– 非静态方法可以访问静态成员

### 演示Staic关键字的例子

*E:\01\01 Java\day07\code\StaticTest2.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
/*
演示Static关键字
*/
public class StaticTest2{
	static String country="China";
	String name;
	
	public void show(){
		System.out.println(country + " - " + name);
	}
}

*E:\01\01 Java\day07\code\StaticTest2Demo.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
演示StaticTest2类
*/
public class StaticTest2Demo{
	public static void main(String[] args){
		StaticTest2 st1 = new StaticTest2();
		st1.name="Leon";
		st1.show();
		
		StaticTest2 st2 = new StaticTest2();
		st2.name="Tom";
		st2.country="USA";
		st2.show();
	}
}

### 静态变量和实例变量之间的区别
– 所属不同
– 静态变量属于类,也称为类变量
– 实例变量属于对象,也称为对象(实例)变量
– 在内存中的位置不同
– 静态变量在方法区中
– 实例变量在堆内存
– 生命周期不同
– 静态变量随着类的加载而加载,随着类的消失而消失
– 实例变量随着对象的创建而存在,随着对象的消失而消失
– 调用方法不同
– 静态变量可以通过类名和对象名两种方式调用,推荐使用类名调用
– 实例变量只能使用对象名的方式调用

## main方法传参与格式说明
public static void main(String[] args){…}

– public: 修饰符,用来控制访问权限的。
– static: 修饰main方法属于类方法,通过类名直接调用,JVM不用创建对象即可直接调用。
– void: 返回值为空,main方法不用返回任何值。
– main: 默认的程序入口,不是关键字,JVM从这里开始执行。
– String[] args: 形参列表,String类型的数组。
– args: 形参名,也就数数组名。

如何使用?早期可以从键盘输入,但后面JDK1.5以后则被Scanner取代。如图所示:

代码实例:
*E:\01\01 Java\day07\code\Args.java*

Select Code
1
2
3
4
5
6
7
8
9
10
/*
	试验main方法的参数传递
	*/
	public class Args{
		public static void main(String[] args){
			for(int i=0; i<args.length; i++){
				System.out.println(args[i]);
			}
		}
	}

## 工具类的制作
1. 写一个类,包含一个方法用来遍历一维数组。
2. 使用static修饰,可以直接使用类名来调用,方法在main中调用。
3. 将这个类单独放到一个文件中,形成工具类。
4. 可以继续定义更多的关于数组的操作,获得最值等,丰富工具类。

注意:
– 编译的时候,只编译测试类即可
– 通过类名和对象名的方式都能调用,如果不想让使用对象名的方式调用的话,将构造方法私有化即可

### 制作一个工具类实例

代码实例:
*E:\01\01 Java\day07\code\ArrayTool.java*

Select Code
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
36
/*
	求一个求数组的最值工具类
	@author webjust
	@version 1.0
	*/
	public class ArrayTool{
		/**
		* 求最大值
		* @param arr 需要查找最大值的数组
		* @return 返回数组的最大值
		*/
		public static int getMax(int[] arr){
			int max = arr[0];
			for(int i=1; i<arr.length; i++){
				if(arr[i] > max){
					max=arr[i];
				}
			}
			return max;
		}
		
		/**
		* 求最小值
		* @param arr 需要查找最小值的数组
		* @return 返回数组的最小值
		*/
		public static int getMin(int[] arr){
			int min = arr[0];
			for(int i=1; i<arr.length; i++){
				if(arr[i] < min){
					min=arr[i];
				}
			}
			return min;
		}
	}

*E:\01\01 Java\day07\code\ArrayToolTest.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
/*
	测试工具类
	*/
	public class ArrayToolTest{
		public static void main(String[] args){
			int[] arr = {1,2,4,7,9,10};
			int max = ArrayTool.getMax(arr);
			int min = ArrayTool.getMin(arr);
			System.out.println(max + " - " + min);
		}
	}

### 工具类说明书的制作
– 写一个完整的工具类,需要使用public修饰
– 类名上加@author, @version标签
– 方法上加@param, @return标签
– 注意:方法上标签中不用加类型
– 最终使用命令生成文档:`javadoc -d mydoc -version -author ArrayTool.java`

生成的doc文档如图:

## API文档

– 在线版
– 离线版
– 关注事项
– 所在包
– 构造方法
– 形参,返回值类型
– 是否是static静态的
– 从哪个版本开始的

代码实例:
*E:\01\01 Java\day07\code\MathDemo.java*

Select Code
1
2
3
4
5
6
7
8
9
/*
API文档的使用:Math类
*/
public class MathDemo{
	public static void main(String[] args){
		System.out.println(Math.max(1, 8));	//8
		System.out.println(Math.min(-1, 2));//-1
	}
}

## 代码块
局部代码块:
在方法内部,用于限定变量的生命周期,及时释放内存。

构造代码块:
定义在成员位置,用于抽取不同构造方法中相同的部分。构造方法调用一次,构造代码块就执行一次。

静态代码块:
static修饰的构造代码块,用于对类进行初始化。静态代码块随着类的加载而执行,整个过程中只执行一次。

代码演示实例:
*E:\01\01 Java\day07\code\BlockDemo.java*

Select Code
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
36
37
38
39
40
41
42
43
44
45
/*
代码块测试类
*/
class BlockTest{
	static int num;
	
	//构造代码块:在任何一个构造方法前都执行一次
	{
		System.out.println("欢迎来到:");
	}
	
	//静态代码块:对类进行初始化,在类开始加载时就执行,整个过程只执行一次
	static {
		System.out.println("静态代码块1");
	}
	static {
		System.out.println("静态代码块2");
	}
	
	public BlockTest(){
		System.out.println("欢迎来到1:");
		System.out.println("无参构造方法");
	}
	public BlockTest(int num){
		System.out.println("欢迎来到2:");
		System.out.println("带参构造方法");
	}
	
	//局部代码块演示
	public void show(){
		{
			int a=10;
		}
		{
			int a=20;
		}
	}
}

public class BlockDemo{
	public static void main(String[] args){
		BlockTest bt1=new BlockTest();
		BlockTest bt2=new BlockTest(1);
	}
}

面试题:静态代码块,构造代码块,构造方法的执行顺序和特点?
答:静态代码块 -> 构造代码块 -> 构造方法。

## 继承 extends
– 多个类中存在多个相同的属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只需从抽取出来的那那个类扩展(extends)即可
– 需要扩展的类称为子类,抽取出来的那个类称为父类,或者超类,或者基类
– 通过关键字 extends 让类与类之间产生继承关系

class 子类名 extends 父类{/*类体*/}

继承的出现,提高了代码的可复用性。

继承的出现让类和类之间开始产生了关系,提供了多态的前提。

代码实例:

*E:\01\01 Java\day07\code\Stu.java*

Select Code
1
2
3
4
5
6
/*
继承:继承人类
*/
class Stu extends Human{
	
}

*E:\01\01 Java\day07\code\Human.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
/*
继承:基类
*/
class Human{
	public void eat(){
		System.out.println("eat....");
	}
	public void sleep(){
		System.out.println("sleep....");
	}
}

*E:\01\01 Java\day07\code\Teacher.java*

Select Code
1
2
3
4
5
6
/*
继承:继承人类
*/
class Teacher extends Human{

}

*E:\01\01 Java\day07\code\HumanDemo.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*
继承的测试
*/
public class HumanDemo{
	public static void main(String[] args){
		Stu s = new Stu();
		s.eat();
		s.sleep();
		
		Teacher t = new Teacher();
		t.eat();
		t.sleep();
	}
}

### 继承的特点
– Java只支持单继承,不支持多继承。一个类只能有一个父类,不能由多个父类。
– Java支持多层继承
– 定义继承需要注意,不仅要为了获得其他类的某个功能才去继承。类与类之间,需要有所属关系,即子类是父类的一种。
– 私有成员不能被继承
– 继承关系中成员变量的关系:子类中方法使用变量的“就近原则”
– 1. 现在子类方法中查找
– 2. 再在子类的成员变量中查找
– 3. 再找父类的成员变量

实例1:

*E:\01\01 Java\day07\code\ExtendDemo.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
测试一个类只能继承一个父类
*/
class A{
	
}
class B{
	
}
class C extends A,B{
	
}

public class ExtendDemo{
	public static void main(String[] args){
		
	}
}

实例2:

*E:\01\01 Java\day07\code\ExtendDemo2.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
继承特点:不能继承私有成员
*/
class A{
	private int num = 1; //num 在 A 中是 private 访问控制
	//int num = 1;
}

class B extends A{
	public void show(){
		System.out.println(num);
	}
}

public class ExtendDemo2{
	public static void main(String[] args){
		B b1 = new B();
		b1.show();
	}
}

实例3:

*E:\01\01 Java\day07\code*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
继承特性:就近原则
方法内 > 本类中 > 继承属性
*/
class A{
	int num = 1;
}

class B extends A{
	int num = 2;
	public void show(){
		int num = 3;
		System.out.println(num);
	}
}

public class ExtendDemo3{
	public static void main(String[] args){
		B b1 = new B();
		b1.show();	//3
	}
}

## super 关键字
– super和this的用法类似
– this代表本类对象的引用
– super代表父类对象的内存空间的标识

### super的使用场景
子父类出现同名成员时,用super进行区分:
– super.成员属性
– super.成员方法()
子类使用super调用父类的构造方法
– super(…)

实例:

*E:\01\01 Java\day07\code\SuperDemo.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
super关键字
*/
class A{
	int num=10;
}
class B extends A{
	int num=20;
	public void show(){
		System.out.println(num);	//20
		System.out.println(super.num);	//10
	}
}

public class SuperDemo{
	public static void main(String[] args){
		B b1 = new B();
		b1.show();
	}
}

代码实例:

*E:\01\01 Java\day07\code\SuperDemo2.java*

Select Code
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
/*
Super关键字特性
*/
class A{
	int num=10;
	public A(){
		System.out.println("父类无参构造方法");
	}
	public A(String s){
		System.out.println(s);
		System.out.println("父类带参构造方法");
	}
}
class B extends A{
	int num=20;
	//程序会默认先执行B类的无参构造方法,然后执行父类的无参构造方法
	public B(){
		//必须在程序的第一行,显示的调用父类的带参的构造方法,使用Super关键字表示是父类
		super("1000"); //不放在第一行,会报错
		System.out.println("子类无参构造方法重写...");
	}
	public void show(){
		System.out.println(num);	//20
		System.out.println(super.num);	//10
	}
}

public class SuperDemo2{
	public static void main(String[] args){
		B b1 = new B();
		b1.show();
	}
}

## 方法重写 Override|Overwrite
– 子类中出现与父类一模一样的方法时,会出现覆盖操作,也称为重写或者复写
– 父类中的私有方法不可以被重写
– 在子类重写方法中,继续使用被重写的方法可以使用super.方法名(…)
– 覆盖注意事项:覆盖时,子类方法权限一定要大于等于父类的方法权限;除了访问权限外,其他部分和父类保持一致;静态只能覆盖静态;
– 覆盖的应用:当子类需要父类的功能,而功能主体子类有自己的特有内容时,可以复写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容

代码实例:

*E:\01\01 Java\day07\code\OverrideDemo.java*

Select Code
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
36
37
38
39
/*
方法重写实例
*/
class Father{
	public void test(){
		System.out.println("Father test()...");
	}
	public static void test2(){
		System.out.println("Father test2()...");
	}
	void test3(){
		System.out.println("Father test3()...");
	}
}

class Son extends Father{
	//重写父类方法,需要同名方法
	public void test(){
		super.test();	//在子类中调用父类的方法
		System.out.println("Son test()...");
	}
	//重写静态方法,子类必须也是静态方法
	public static void test2(){
		System.out.println("Son test2()...");
	}
	//子类的权限范围必须大于父类的方法
	public void test3(){
		System.out.println("Son test3()...");
	}
}

public class OverrideDemo{
	public static void main(String[] args){
		Son s = new Son();
		s.test();
		s.test2();
		s.test3();
	}
}

### 子类的实例化过程
– 子类中所有的构造方法默认都会访问父类中的空参构造方法,因为每一个构造方法的第一行都有一条默认的语句super(),除非第一行是用this或super显示调用了其他的构造方法
– 子类会具备父类中的数据,所以要先明确父类是如何对这些数据初始化的,也就是父类对象必需在子类对象初始化前初始化ok
– 当父类中没有空参构造方法时,子类的构造方法必须通过this或super语句指定要访问的构造方法

代码实例:

*E:\01\01 Java\day07\code\OverrideDemo2.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
方法重写实例
*/
class Father{
	public Father(){
		System.out.println("Father构造方法");
	}
}

class Son extends Father{
	public Son(){
		super();	//默认会添加父类的无参构造方法,也可以指定为其他的父类构造方法
		System.out.println("Son构造方法");
	}
}

public class OverrideDemo2{
	public static void main(String[] args){
		Son s = new Son();
	}
}

## final 关键字
final可以修饰类、方法、变量。
图oop-10.jpg

final修饰的成员变量,必须在构造方法执行完成之前初始化:
1. 可以在定义的时候就赋值(最常见)
2. 可以在构造代码块中赋值,多个构造代码块中不能重复赋值

代码实例:

*E:\01\01 Java\day07\code\FinalDemo.java*

Select Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
final关键字
*/
class A{
	public final int num;
}
class B extends A{
	int num=20;
	public void show(){
		System.out.println(num);
	}
}

public class FinalDemo{
	public static void main(String[] args){
		B b1=new B();
		b1.show();
	}
}

## 抽象类
### 1. 抽象类概述
抽象定义:抽象就是从多个事物中将共性的,本质的内容抽取出来
抽象类定义:Java中可以定义没有方法体的方法,该方法的具体实现由子类来完成,该方法称为抽象方法,包含抽象方法的类就是抽象类。
抽象方法的由来:多个对象都具备相同的功能,但是功能的具体实现有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。

> 如果在父类中定义了一个各子类都有不同实现的方法,那么子类需要重写这个方法,为什么父类还要定义这个方法?这是为多态做准备。

由于多态的要求:父类引用指向子类实例,但父类不能调用子类独有的方法,为了使用多态,父类中必须定义这个方法,但是方法的实现又会被子类重写。
为了既能使用多态,又能省去在父类中的麻烦,Java提供了抽象方法,在父类中只定义方法名,不实现方法体。

图oop-10.jpg

### 2. 抽象类特点
抽象类和抽象方法必须用abstract关键字来修饰。
抽象方法只有方法声明,没有方法体,定义在抽象类中。
抽象类不可以被实例化,原因如下:
– 抽象类是具体事物抽象出来的,本身不是具体的,没有对应的实例。
– 假设抽象类可以创建对象,那么调用其抽象方法,将无意义。
抽象类通过其子类实例化,而子类需要实现抽象类中所有的抽象方法后才能创建对象,否则该子类也是抽象类。

修饰符 abstract 返回值类型 方法名(参数列表);

### 3. 抽象类举例代码
子类Dog, Cat分别实现Animal类的抽象方法eat()。

2个代码实例

### 4. 抽象类相关问题
– 抽象类是否可以有构造方法?
抽象类中可以有成员变量,而构造方法的作用就是对成员变量初始化的,所以可以有构造方法。

– 抽象关键字abstract不可以和哪些关键字共存?
static, final, private

– 抽象类中可不可以没有抽象方法?
可以,比如可以不让外界实例化。

## 接口
类可以继承一个类的同时实现多个接口

class Dog extends Animal implements CanJump,CanWin{

}

接口与接口之间是继承关系

public interface InterfaceA{void m1();}
public interface InterfaceB{void m2();}
public interface InterfaceC extends InterfaceA,InterfaceB{
//有两个抽象方法继承至父类接口;
}

接口是抽象的一种机制。

现实事物的共性抽取成类:
将不同类中的同名方法抽象成抽象方法,形成抽象类。
对类的成员变量和方法继续抽象的话,就形成接口,接口是类的最高级别的抽象机制。

接口中只有常量和抽象方法
接口是一种规范,实现一个接口,就需要实现其中所有的抽象方法。

格式:

Select Code
1
2
3
4
[public] interface 接口名 [extends 父接口1,父接口2...]{
	//成员常量: public static final
	//抽象方法: public abstract
}

– public: 可以在所有包中访问,不加的话,表明只能在本包中访问该接口
– 接口中的成员修饰符是固定的,写与不写都有
– 成员常量: public static final
– 抽象方法: public abstract
– 接口中的成员都是public修饰的。
– 接口的出现将”多继承”通过另外一种形式体现出来,即”多实现”。

### 接口的特点
接口是程序的扩展功能:想给类A增加一个功能,只需要定义一个接口,然后自定义一个类,继承自类A,并实现这个接口,即可完成把类A的功能扩展。


*E:\01\01 Java\day07\code\InterfaceDemo.java*

Select Code
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
/*
接口:对功能的扩展
*/
class Dog{
	public void eat(){
		System.out.println("Dog eat()....");
	}
}

interface Jump{
	public abstract void jump();
}

class JumpDog extends Dog implements Jump{
	public void jump(){
		System.out.println("Dog jump()....");
	}
}

public class InterfaceDemo {
	public static void main(String[] args){
		JumpDog jd = new JumpDog();
		jd.eat();
		jd.jump();
	}
}

– 接口的出现降低耦合性
接口只定义规范,不关心实现,这是设计和实现相分离的表现。

– 接口可以用来多实现

Select Code
1
2
3
class SuperMan implements CanFly,CanSwin,CanFight{
	//实现在所有接口中定义的抽象方法
}

#大数据学习笔记# 汇总

Java


Linux


Hadoop


Zookeeper


Hive


# 10小时入门大数据 # 学习笔记

## 第1章 大数据概述 ##
### 1-1 导学
学习本项目的前置基础知识要求:

– 了解J2SE编程
– 懂得JAVA语法
– 了解J2SE基础知识
– 了解LINUX常用基本命令的使用

环境介绍:

– Linux版本:CentOS 6.4
– Hadoop版本:CDH5.7
– 开发工具:IDAE

课程安排:

– 大数据概述
– 初识Hadoop
– 分布式文件系统HDFS
– 分布式资源调度YARN
– 分布式计算框架MapReduce
– Hadoop项目实战
– Hadoop分布式集群搭建
– Hadoop集成Spring的使用
– 前言技术拓展:Spark/Flink/Bean
– Hadoop3.x新特性

### 1-2 课程安排
– 大数据故事
– 大数据背景
– 大数据基本概念
– 大数据涉及到的技术
– 大数据带来的技术挑战
– 大数据带来的思维变革

### 1-3 两个案例
– 莱曼世界杯扑出点球的纸条
– 电商把假货卖给谁

### 1-4 大数据与生活息息相关

### 1-5 大数据基本概念
图:4V特征

图:大数据要解决的问题

### 1-6 大数据所面对的技术挑战
大数据涉及到的技术:

– 数据采集
– 数据存储
– 数据处理/分析/挖掘
– 可视化

大数据在技术架构上带来的挑战

– 对现有的数据库管理技术的挑战
– 经典数据库技术没有考虑数据的多类别
– 实时性的技术挑战
– 网络架构、数据中心、运维的挑战

大数据带来的其他挑战

– 数据隐私
– 数据源复杂多样

### 1-7 如何应对大数据带来的挑战
挑战分析之如何对大数据进行存储和分析呢?

图:大数据存储和分析

开源实现:Hadoop

### 1-8 如何学好大数据
– 官网、官网、官网
– 英文、英文、英文
– 项目实战对知识点进行巩固和融会贯通
– 社区活动:开源社区大会、线下沙龙等
– 切记:多动手、多练习、贵在坚持

## 第2章 初识Hadoop ##
### 2-1 章节安排
– Hadoop概述
– Hadoop核心组件
– Hadoop优势
– Hadoop发展史
– Hadoop生态系统
– Hadoop发行版的选择
– Hadoop企业应用案例

### 2-2 Hadoop概述
图1:名字的由来

Hadoop项目作者的孩子给一个棕黄色的大象样子的填充玩具的命名。

图2:官网的说明

图3:Hadoop介绍

图4:Hadoop能做什么

### 2-3 Hadoop核心组件
分布式文件系统HDFS:

– 源自于Google的FDS论文,论文发表于2003年10月
– HDFS的GFS克隆版
– HDFS特点:扩展性、容错性、海量数据存储
– 将文件分成指定大小的数据块并以多副本的存储在多个机器上
– 数据切分、多副本、容错等操作对用户是透明的

图5:分布式文件系统HDFS

资源调度系统YARN:

– YARN: Yet Another Resource Negotiator
– 负责整个集群资源的管理和调度
– YARN特点:扩展性、容错性、多框架资源统一调度(2.0)

图6:资源调度系统YARN

分布式计算框架MapReduce

– 源自于Google的MapReduce论文,论文发表于2004年12月
– MapReduce是Google MapReduce的克隆版
– MapReduce特点:扩展性、容错性、海量数据离线处理

图7:分布式计算MapReduce

### 2-4 Hadoop优势
高可靠性

– 数据存储:数据块多副本
– 数据计算:重新调度作业计算

高扩展性

– 存储/计算资源不够时,可以横向的线性扩展机器
– 一个集群中可以包含数以千计的节点

其他

– 存储在廉价机器上,降低成本
– 成熟的生态圈

### 2-5 Hadoop发展史
文章:《Hadoop十年解读与发展预测》

### 2-6 Hadoop生态系统
狭义Hadoop:是一个适合大数据分布式存储、分布式计算、和资源调度的平台。

广义Hadoop:指的是整个Hadoop生态系统,Hadoop生态系统是一个很庞大的概念,Hadoop是其中最重要最基础的一个部分;生态系统中的每一个子系统只解决某一个特定的问题域,不搞统一型的一个全能系统,而是小而精的多个小系统。

图8:Hadoop生态系统

特点:

– 开源、社区活跃
– 囊括了大数据处理的方方面面
– 成熟的生态圈

### 2-7 Hadoop发行版的选择
常用发行版和选型:

– Apache Hadoop
CDH:Cloudera Distributed Hadoop
– HDP:Hortonworks Data Platform

图9-10:CDH发行版

### 2-8 Hadoop企业应用案例
图11:消费大数据之亚马逊预测式发货

图12:商品零售大数据

## 第3章 分布式文件系统HDFS ##
### 3-1 章节安排
– HDFS概述及设计目标
– HDFS架构
– HDFS副本机制
– HDFS环境搭建(伪分布式)
– HDFS shell
– JAVA API操作HDFS
– HDFS文件读写流程(重点)
– HDFS优缺点

问题:如果让我们来设计一个分布式文件系统,怎么做?

图1:自定义分布式文件系统

HDFS是按照每个文件先进行拆分,拆分成块,每个块的大小我们可以进行设置,一般设置成128M。

### 3-2 HDFS概述及设计目标
什么是HDFS?

– Hadoop实现了一个分布式文件系统,简称HDFS(Hadoop Distributed File System)。
– 源自于Google的GFS论文
– 发表于2003年,HDFS是GFS的克隆版

设计目标:

– 非常巨大的分布式文件系统
– 运行在廉价的硬件上
– 易扩展、为用户提供性能不错的文件存储服务

官方链接:https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/HdfsUserGuide.html

图2:官网HDFS介绍

### 3-3 HDFS架构
图3:HDFS架构图

官网原文:NameNode and DataNodes

HDFS has a master/slave architecture. An HDFS cluster consists of a single NameNode, a master server that manages the file system namespace and regulates access to files by clients. In addition, there are a number of DataNodes, usually one per node in the cluster, which manage storage attached to the nodes that they run on. HDFS exposes a file system namespace and allows user data to be stored in files. Internally, a file is split into one or more blocks and these blocks are stored in a set of DataNodes. The NameNode executes file system namespace operations like opening, closing, and renaming files and directories. It also determines the mapping of blocks to DataNodes. The DataNodes are responsible for serving read and write requests from the file system’s clients. The DataNodes also perform block creation, deletion, and replication upon instruction from the NameNode.

The NameNode and DataNode are pieces of software designed to run on commodity machines. These machines typically run a GNU/Linux operating system (OS). HDFS is built using the Java language; any machine that supports Java can run the NameNode or the DataNode software. Usage of the highly portable Java language means that HDFS can be deployed on a wide range of machines. **A typical deployment has a dedicated machine that runs only the NameNode software. Each of the other machines in the cluster runs one instance of the DataNode software.** The architecture does not preclude running multiple DataNodes on the same machine but in a real deployment that is rarely the case.

The existence of a single NameNode in a cluster greatly simplifies the architecture of the system. The NameNode is the arbitrator and repository for all HDFS metadata. The system is designed in such a way that user data never flows through the NameNode.

1个Master(NameNode,简称NN),带N个Slave(DataNode,简称DN)。1个文件会被拆分成多个Block,blocksize:128M。

NN负责处理:

  • (1)负责客户端请求的响应
  • (2)负责元数据[文件的名称\副本系数\Block存放的DN]的管理。

DN负责处理:

  • (1)存储用户的文件对应的数据块
  • (2)要定期向NN发送心跳信息,汇报本身及其所有的block信息,健康状况。

### 3-4 HDFS副本机制

HDFS supports a traditional hierarchical file organization. A user or an application can create directories and store files inside these directories. The file system namespace hierarchy is similar to most other existing file systems; one can create and remove files, move a file from one directory to another, or rename a file.

The NameNode maintains the file system namespace. Any change to the file system namespace or its properties is recorded by the NameNode. An application can specify the number of replicas of a file that should be maintained by HDFS. The number of copies of a file is called the replication factor(副本系数,副本因子) of that file. This information is stored by the NameNode.

HDFS is designed to reliably store very large files across machines in a large cluster. It stores each file as a sequence of blocks. The blocks of a file are replicated for fault tolerance. The block size and replication factor are configurable per file.

All blocks in a file except the last block are the same size, while users can start a new block without filling out the last block to the configured block size after the support for variable length block was added to append and hsync.

An application can specify the number of replicas of a file. The replication factor can be specified at file creation time and can be changed later. Files in HDFS are write-once (except for appends and truncates) and have strictly one writer at any time.

The NameNode makes all decisions regarding replication of blocks. It periodically receives a Heartbeat and a Blockreport from each of the DataNodes in the cluster. Receipt of a Heartbeat implies that the DataNode is functioning properly. A Blockreport contains a list of all blocks on a DataNode.

图4:HDFS副本机制&Block信息

### 副本存放策略
图5:副本存放策略:分机架、分节点

### 3-5 HDFS环境搭建(伪分布式)
cdh下载地址:http://archive.cloudera.com/cdh5/cdh/5/hadoop-2.6.0-cdh5.7.0/hadoop-project-dist/hadoop-common/SingleCluster.html

http://archive.cloudera.com/cdh5/cdh/5/

图6:官网介绍安装前准备

Hadoop伪分布式安装步骤:

1)安装JDK详细步骤

– 解压:`tar -zxvf jdk-7u79-linux-x64.tar.gz -C ~/app`
– 添加到系统环境变量:`~\.bash_profile`
– export JAVA_HOME=/home/hadoop/app/jdk1.7.0_79
– export PATH=$JAVA_HOME/bin:$PATH
– 使得环境变量生效:`source ~/.bash_profile`
– 验证JAVA是否配置成功:java -version

2)SSH免密码配置详细步骤

– sudo yum install ssh
– ssh -keygen -t rsa
– `cp ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys`

3)下载并解压Hadoop

## 第4章 分布式资源调度YARN ##

## 第5章 分布式计算框架MapReduce ##

## 第6章 Hadoop项目实战 ##

## 第7章 Hadoop分布式集群搭建 ##

## 第8章 Hadoop集成Spring的使用 ##

## 第9章 前沿技术拓展Spark,Flink,Beam ##

## 第10章 Hadoop3.x新特性 ##