#大数据学习笔记第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{
	//实现在所有接口中定义的抽象方法
}

面向对象入门案例:封装一个数据库操作Model类

面向对象编程思维的访问轨迹:
1、实例化1个对象
2、查看对象的实例化:初始化数据库的连接;把数据表传参给一个变量
3、对象访问的成员方法
4、查看对象的成员方法
5、成员方法的运行代码:声明1个SQL语句遍历,作为参数传给一个成员方法
6、查看成员方法的代码:数据库的查询操作,返回查询的结果
7、对象调用的成员方法结束,返回结果给调用者!

运用的面向对象知识:
1、外部访问成员方法:连贯操作
$res = new Model(‘user’); //创建一个对象
$res->field(array(‘id’, ‘username’, ‘fullname’))->limit(3)->select(); //使用创建的对象$res,调用类中的公有方法

2、代码重用性:对象自身访问成员方法(辅助方法,封装性)
如:protected function query() //这种辅助的操作方法可以修饰词可以是private或protected
{
//sql语句执行语句,返回操作后的结果
}
3、伪变量$this,表示对象自己本身

源码:https://github.com/webjust/case-study/tree/master/Model

备注:
public: 自己,外部,家族均可以访问
private:只有自己可以访问(使用$this内部访问)
protected:除了外部以外,都可以访问,一般用于继承的类的情况