1. 面向对象与面向过程
都是编程思想
面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做。
面向对象:强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
举例对比:人把大象装进冰箱。
2. 类与对象
2.1. 面向对象学习的三条主线
Java类及类的成员:属性、方法、构造器;代码块、内部类
面向对象的大特征:封装性、继承性、多态性、(抽象性)
其它关键字:this、super、static、final、abstract、interface、package、import等
“大处着眼,小处着手”
面向对象学习
1、类与对象
(1)类与对象的概念
(2)类与对象的关系
(3)如何设计类,类的成员
(4)如何创建对象
2、面向对象的三个基本特征和高级特性
基本特性
封装
继承
多态
高级特性
枚举
接口
抽象
泛型
注解
可变参数
自动装箱与拆箱
foreach
Lambda表达式
...
3、相关的关键字和API
关键字
class
this
权限修饰符
public
protected
缺省
private
super
集合
异常
网络编程
线程
..
2.2. 完成一个项目(或功能)的思路:
2.3. 面向对象中类与对象的概念和关系
类:对一类事物的描述,是抽象的、概念上的定义
对象:是实际存在的该类事物的每个个体,因而也称为实例(instance)
面向对象程序设计的重点是类的设计
设计类,就是设计类的成员。
类与对象的关系
类是对象的设计图,创建的模板
对象是类的实例,是一个具体的个体
2.4. 面向对象思想落地实现的规则
1. 创建类,设计类的成员
2. 创建类的对象
3. 通过“对象.属性”或“对象.方法”调用对象的结构
补充:几个概念的使用说明
属性 = 成员变量 = field = 域、字段
方法 = 成员方法 = 函数 = method
创建类的对象 = 类的实例化 = 实例化类
2.5. 对象的创建与对象的内存解析
典型代码:
Person p1 = new Person();
Person p2 = new Person();
Person p3 = p1;//没有新创建一个对象,共用一个堆空间中的对象实体。说明:
如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的)
意味着:如果我们修改一个对象的属性a,则不影响另外一个对象属性a的值。
内存解析图示
2.6. 匿名对象:我们创建的对象,没显式的赋给一个变量名。即为匿名对象
特点:匿名对象只能调用一次。
举例:
new Phone().sendEmail();
new Phone().playGame();
new Phone().price = 1999;
new Phone().showPrice();//0.0应用场景:
PhoneMall mall = new PhoneMall();
//匿名对象的使用
mall.show(new Phone());
其中,
class PhoneMall{
public void show(Phone phone){
phone.sendEmail();
phone.playGame();
}2.7. 理解"万事万物皆对象"
在Java语言范畴中,我们都将功能、结构等封装到类中,通过类的实例化,来调用具体的功能结构
Scanner,String等
文件:File
网络资源:URL
涉及到Java语言与前端Html、后端的数据库交互时,前后端的结构在Java层面交互时,都体现为类、对象。
2.8. 扩展:JVM内存结构
编译完源程序以后,生成一个或多个字节码文件。
我们使用JVM中的类的加载器和解释器对生成的字节码文件进行解释运行。意味着,需要将字节码文件对应的类加载到内存中,涉及到内存解析。
《JVM规范》
虚拟机栈:即为平时提到的栈结构。我们将局部变量存储在栈结构中
堆:我们将new出来的结构(比如:数组、对象)加载在对空间中。补充:对象的属性(非static的)加载在堆空间中。
方法区:类的加载信息、常量池、静态域
3. 类的结构之一:属性
类的设计中,两个重要结构之一:属性
3.1. 属性的特点
(1)声明的位置
在类中方法外
(2)保存的位置
static
在方法区
非static
在堆中
(3)默认值
byte,short,int,long是0,float,double是0.0,boolean是false,char是u0000,引用数据类型都是null
(4)作用域
在整个类中
(5)生命周期
随着对象的创建而创建,到垃圾回收为止
属性声明格式
[修饰符] 数据类型 属性名 【=显式值】;
3.2. 对比:属性 vs 局部变量
3.2.1. 相同点
定义变量的格式:数据类型 变量名 = 变量值
先声明,后使用
变量都其对应的作用域
3.2.2. 不同点
2.1 在类中声明的位置的不同
属性:直接定义在类的一对{}内
局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量
2.2 关于权限修饰符的不同
属性:可以在声明属性时,指明其权限,使用权限修饰符。
常用的权限修饰符:private、public、缺省、protected --->封装性
目前,大家声明属性时,都使用缺省就可以了。
局部变量:不可以使用权限修饰符。
2.3 默认初始化值的情况:
属性:类的属性,根据其类型,都默认初始化值。
整型(byte、short、int、long:0)
浮点型(float、double:0.0)
字符型(char:0 (或u0000))
布尔型(boolean:false)
引用数据类型(类、数组、接口:null)
局部变量:没默认初始化值。
意味着,我们在调用局部变量之前,一定要显式赋值。
特别地:形参在调用时,我们赋值即可。
2.4 在内存中加载的位置:
属性:加载到堆空间中 (非static)
局部变量:加载到栈空间
3.3. 补充:回顾变量的分类
方式一:按照数据类型:
方式二:按照在类中声明的位置:
4. 类的结构之二:方法
方法(Method):又称为函数(Function),代表一个独立功能,目的为了代码重用
4.1. 方法的声明
【修饰符列表】 返回值类型 方法名(【形参列表】)【抛出异常列表】{
方法体,方法功能的实现代码;
【return 【返回值】;】
}注意:static、final、abstract 来修饰的方法,后面再讲。
四种形式
1、无参无返回值
[修饰符列表] void 方法名()[抛出的异常列表]{
方法体;
}public static void 方法名(){
方法体;
}2、有参无返回值
[修饰符列表] void 方法名(形参列表)[抛出的异常列表]{
方法体;
}public static void 方法名(形参列表){
方法体;
}3、无参有返回值
[修饰符列表] 返回值类型 方法名()[抛出的异常列表]{
方法体;
}public static 返回值类型 方法名(){
方法体;
return 返回值;
}4、有参有返回值
[修饰符列表] 返回值类型 方法名(形参列表)[抛出的异常列表]{
方法体;
}public static 返回值类型 方法名(形参列表){
方法体;
return 返回值;
}说明
3.1 关于权限修饰符:默认方法的权限修饰符先都使用public
Java规定的4种权限修饰符:private、public、缺省、protected -->封装性再细说
3.2 返回值类型: 返回值 vs 没返回值
3.2.1 如果方法返回值,则必须在方法声明时,指定返回值的类型。同时,方法中,需要使用return关键字来返回指定类型的变量或常量:“return 数据”。如果方法没返回值,则方法声明时,使用void来表示。通常,没返回值的方法中,就不需要使用return.但是,如果使用的话,只能“return;”表示结束此方法的意思。
3.2.2 我们定义方法该不该返回值?
①题目要求
②凭经验:具体问题具体分析
3.3 方法名:属于标识符,遵循标识符的规则和规范,“见名知意”
3.4 形参列表: 方法可以声明0个,1个,或多个形参。
3.4.1 格式:数据类型1 形参1,数据类型2 形参2,..
3.4.2 我们定义方法时,该不该定义形参?
① 题目要求
② 凭经验:具体问题具体分析
3.5 方法体:方法功能的体现.
4.2. 方法的调用
本类中:不需要在方法名前面加前缀
其他类中:需要在方法名前面加前缀
如果被调用的方法是static
前缀是 类名.
类名.方法名
如果被调用的方法是非static
前缀是 对象名.
对象名.方法名
不管是本类中还是其他类中,对于方法签名的关注点是一样:
【修饰符列表】 返回值类型 方法名(【形参列表】)【抛出异常列表】
目前
有无形参列表
如果有形参,调用是必须传实参,而且实参的个数与形参的个数一致,类型兼容
如果没有形参,调用是也不用传实参
有无返回值
如果有返回值,调用时就可以接受
如果无返回值,调用时不能用变量接收,只能单独成一个语句
四种形式
1、无参无返回值
本类中
方法名();
单独一个语句
其他类中
类名.方法名();
单独一个语句
对象名.方法名();
单独一个语句
2、有参无返回值
本类中
方法名(实参列表);
单独一个语句
其他类中
类名.方法名(实参列表);
单独一个语句
对象名.方法名(实参列表);
单独一个语句
3、无参有返回值
本类中
变量 = 方法名();
方法的调用作为表达式
把方法调用的返回值赋值给变量
其他类中
变量 = 类名.方法名();
方法的调用作为表达式
把方法调用的返回值赋值给变量
变量 = 对象名.方法名();
方法的调用作为表达式
把方法调用的返回值赋值给变量
4、有参有返回值
本类中
变量 = 方法名(实参列表);
方法的调用作为表达式
把方法调用的返回值赋值给变量
其他类中
变量 = 类名.方法名(实参列表);
方法的调用作为表达式
把方法调用的返回值赋值给变量
变量 = 对象名.方法名(实参列表);
方法的调用作为表达式
把方法调用的返回值赋值给变量
4.3. 方法的重载
4.3.1. 方法的重载的概念
定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
总结:"两同一不同":同一个类、相同方法名,参数列表不同:参数个数不同,参数类型不同
4.3.2. 构成重载的举例
举例一:Arrays类中重载的sort() / binarySearch();PrintStream中的println()
举例二:
//如下的4个方法构成了重载
public void getSum(int i,int j){
System.out.println("1");
public void getSum(double d1,double d2){
System.out.println("2");
public void getSum(String s ,int i){
System.out.println("3");
public void getSum(int i,String s){
System.out.println("4");
}不构成重载的举例:
//如下的3个方法不能与上述4个方法构成重载
//public int getSum(int i,int j){
//return 0;
//public void getSum(int m,int n){
//private void getSum(int i,int j){
//}3. 如何判断是否构成方法的重载?
严格按照定义判断:两同一不同。
跟方法的权限修饰符、返回值类型、形参变量名、方法体都没关系!
4.如何确定类中某一个方法的调用:
方法名 ---> 参数列表
面试题:方法的重载与重写的区别?
throws hrow
StringStringBufferStringBuilder
CollectionCollections
finalfinallyfinalize
抽象类、接口
sleep() / wait(
4.3.3. 可变个数形参的方法
1.使用说明:
1.jdk 5.0新增的内容
2.具体使用:
2.1 可变个数形参的格式:数据类型 .. 变量名
2.2 当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,2个,。。。
2.3 可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
2.4 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。换句话说,二者不能共存。
2.5 可变个数形参在方法的形参中,必须声明在末尾
2.6 可变个数形参在方法的形参中,最多只能声明一个可变形参。
2.举例说明:
public void show(int i){
public void show(String s){
System.out.println("show(String)");
public void show(String .. strs){
System.out.println("show(String .. strs)");
for(int i = 0;i < strs.length;i ){
System.out.println(strs[i]);
//不能与上一个方法同时存在
//public void show(String[] strs){
//调用时:
test.show("hello");
test.show("hello","world");
test.show();
test.show(new String[]{"AA","BB","CC"});4.4. java的值传递机制
4.4.1. 针对于方法内变量的赋值举例:
System.out.println("***********基本数据类型:****************");
int m = 10;
int n = m;
System.out.println("m = " m ", n = " n);
n = 20;
System.out.println("m = " m ", n = " n);
System.out.println("***********引用数据类型:****************");
Order o1 = new Order();
o1.orderId = 1001;
Order o2 = o1;//赋值以后,o1和o2的地址值相同,都指向了堆空间中同一个对象实体。
System.out.println("o1.orderId = " o1.orderId ",o2.orderId = " o2.orderId);
o2.orderId = 1002;
System.out.println("o1.orderId = " o1.orderId ",o2.orderId = " o2.orderId);规则:
如果变量是基本数据类型,此时赋值的是变量所保存的数据值。
如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。
4.4.2. 针对于方法的参数概念
形参:方法定义时,声明的小括号内的参数
实参:方法调用时,实际传递给形参的数据
4.4.3. java中参数传递机制:值传递
规则:
如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。
推广:
如果变量是基本数据类型,此时赋值的是变量所保存的数据值。
如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。
4.4.4. 典型例题与内存解析
【例题1】
【例题2】
4.4.5. 递归方法
1.定义:
递归方法:一个方法体内调用它自身。
2.如何理解递归方法?
方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
3.举例:
// 例1:计算1-n之间所自然数的和
public int getSum(int n) {// 3
if (n == 1) {
return 1;
} else {
return n getSum(n - 1);
// 例2:计算1-n之间所自然数的乘积:n!
public int getSum1(int n) {
if (n == 1) {
return 1;
} else {
return n * getSum1(n - 1);
//例3:已知一个数列:f(0) = 1,f(1) = 4,f(n 2)=2*f(n 1) f(n),
//其中n是大于0的整数,求f(10)的值。
public int f(int n){
if(n == 0){
return 1;
}else if(n == 1){
return 4;
}else{
//return f(n 2) - 2 * f(n 1);
return 2*f(n - 1) f(n - 2);
//例4:斐波那契数列
//例5:汉诺塔问题
//例6:快排5. 类的结构之三:构造器
5.1. 构造器(或构造方法):Constructor
构造器的作用:
1. 创建对象
2. 初始化对象的信息
5.2. 构造器的特点
构造器的特点:
(1)构造器名与类名必须相同
(2)构造器没有返回值
(3)构造器可以重载
(4)如果一个类没有声明过构造器,编译器将默认添加一个无参构造
如果这个类声明了构造器,编译器将不再自动添加无参构造
5.3. 声明和调用
如何声明
无参
[修饰符] 类名(){
}有参
[修饰符] 类名(形参列表){
}//构造器
public Person(){
System.out.println("Person()...");
public Person(String n){
name = n;
public Person(String n,int a){
name = n;
age = a;
}如何调用
(1)和new一起
new 构造器()
new 构造器(实参列表)
(2)在本类的其他构造器中或子类的构造器中
在本类的其他构造器中:this()或this(实参列表)
在子类的构造器中:super()或super(实参列表)
6. 关键字:this
可以调用的结构:属性、方法;构造器
this调用属性、方法 : this理解为:当前对象 或 当前正在创建的对象
2.1. 在类的方法中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象属性或方法。但是,
通常情况下,我们都择省略"this."。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式
的使用"this.变量"的方式,表明此变量是属性,而非形参。
2.2. 在类的构造器中,我们可以使用"this.属性"或"this.方法"的方式,调用当前正在创建的对象属性或方法。但是,通常情况下,我们都择省略"this."。特殊情况下,如果构造器的形参和类的属性同名时,我们必须显式的使用"this.变量"的方式,表明此变量是属性,而非形参。
this调用构造器:
①我们在类的构造器中,可以显式的使用"this(形参列表)"方式,调用本类中指定的其他构造器
②构造器中不能通过"this(形参列表)"方式调用自己
③如果一个类中有n个构造器,则最多有 n - 1构造器中使用了"this(形参列表)"
④规定:"this(形参列表)"必须声明在当前构造器的首行
⑤构造器内部,最多只能声明一个"this(形参列表)",用来调用其他的构造器
7. 关键字:package/import
7.1.1. package的使用
1.使用说明:
1.为了更好的实现项目中类的管理,提供包的概念
2.使用package声明类或接口所属的包,声明在源文件的首行
3.包,属于标识符,遵循标识符的命名规则、规范(xxxyyyzzz)、“见名知意”
4.每"."一次,就代表一层文件目录。
2.举例:
举例一:某航运软件系统包括:一组域对象、GUI和reports子系统
举例二:MVC设计模式
3. JDK中的主要包介绍:
7.1.2. import的使用:
import:导入
1. 在源文件中显式的使用import结构导入指定包下的类、接口
2. 声明在包的声明和类的声明之间
3. 如果需要导入多个结构,则并列写出即可
4. 可以使用"xxx.*"的方式,表示可以导入xxx包下的所结构
5. 如果使用的类或接口是java.lang包下定义的,则可以省略import结构
6. 如果使用的类或接口是本包下定义的,则可以省略import结构
7. 如果在源文件中,使用了不同包下的同名的类,则必须至少一个类需要以全类名的方式显示。
8. 使用"xxx.*"方式表明可以调用xxx包下的所结构。但是如果使用的是xxx子包下的结构,则仍需要显式导入
9. import static:导入指定类或接口中的静态结构:属性或方法。