java面向对象三条主线:
-
Java类及类的成员:属性、方法、构造器; 代码块、内部类
-
面向对象三大特征:封装、继承、多态、(抽象)
-
其他关键字:this, super, static, final, abstract, interface, package, import
目录
4.1 面向过程与面向对象
编程思想:编程的原则
1.面向过程(POP) 与 面向对象(OOP)
-
面向过程:强调的 是功能行为,以函数为最小单位,考虑怎么做。
-
面向对象:将功能封装进对 象, 强调具备了功能的对象,以类 / 对象为最小单位, 考虑谁来做 。
例:“人把大象装进冰箱“
2. 面向对象分析方法分析问题的思路和步骤:
-
根据问题需要,选择问题所针对的 现实世界中的实体。
-
从实体中寻找解决问题相关的属性和功能,这些属性和功能就形成了 概念世界中的类。
-
把抽象的实体用计算机语言进行描述,形成计算机世界中类的定义。即借助某种程序 语言,把类构造成计算机能够识别和处理的数据结构。
-
将类实例化成计算机世界中的对象。对象是计算机世界中解决问题的最终工具。
4.2 类和对象
1. 面向对象两个要素
类:对一类事物的描述,是抽象的、概念上的定义。
对象:实际存在的该类事物的每个个体,因而也称为实例(instance)。
面向对象重点是类的设计, 类的设计就是类成员的设计。
4.3 对象的创建和使用
1. 类和对象的使用(面向对象思想落地实现)
1. 创建类,设计类的成员
2. 创建类的对象
3. 调用对象相关结构
//类的构建
class person{
//属性
String name;
int age = 1;
//方法
public void eat(){
System.out.println("吃饭");
}
public void talk(String language){
System.out.println("说话");
}
}
//测试类
//创建类对象
person p1 = new person();
//调用对象的结构:属性、方法
p1.name = "Tom";
p1.talk("Chinese");
注:如果创建多个对象,每个对象都独立拥有一套属性(非static的)。
类的访问:
-
在一个类中的访问机制:类中的方法可以直接访问类中的成员变量。 (例外:static方法访问非static,编译不通过。)
-
在不同类中的访问机制:先创建要访问类的对象,再用对象访问类中 定义的成员。
完整的类构造:
2 内存解析
堆(Heap):
存放对象实例,几乎所有的对象
实例都在这里分配内存。这一点在Java虚拟机规范中的描述是:
所有的
对象实例以及数组都要在堆上分配
。
虚拟机栈:(通常所说的栈)存储
局部变量等。
方法区(Method Area),用于存储已被虚拟机加载的
类信息、常量、静态
变量、即时编译器编译后的代码等数据
。
例:
3 匿名对象
不定义对象的句柄,而直接调用这个对象的方法。
new 类().方法();
-
如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。
-
我们经常将匿名对象作为实参传递给一个方法调用。
4.4 类的成员之一:属性
1 成员变量(属性)vs 局部变量
-
在方法体外,类体内声明的变量称为 成员变量。
-
在方法体内部声明的变量称为 局部变量。
区别:
相同点:
-
定义变量格式相同:数据类型 变量名 = 变量值
-
先声明,后使用。
-
变量都有其对应的作用域。
4.5 类的成员之二:方法
1 定义
方法:描述类应该具有的功能。
比如:Math类:sqrt() random()
Scanner类: nextXxx()
Arrays类:sort() toString() equal()
2 分类
3 说明
1)权限修饰符:private public 缺省 protected
2)返回值类型:如果方法有返回值,则必须在方法声明时,指定返回值类型。方法中需要return关键字返回实例或变量。
注:void中使用return,有结束方法执行的作用
public void a(){
//语句
return;
//语句(不会再执行)
}
3)方法名:标识符
4)方法体:方法功能的体现。
4 方法的调用
注:方法的使用中,可以调用当前类的属性和方法。
练习:
定义类Student,包含三个属性:学号number(int),年级state(int),成绩
score(int)。 创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
问题一:打印出3年级(state值为3)的学生信息。
问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息。
public class StudentTest {
public static void main(String[] args) {
//声明Student类型的数组
Student[] stus = new Student[20]; //String[] arr = new String[10];
for(int i = 0;i < stus.length;i++){
//给数组元素赋值
stus[i] = new Student();
//给Student对象的属性赋值
stus[i].number = (i + 1);
//年级:[1,6]
stus[i].state = (int)(Math.random() * (6 - 1 + 1) + 1);
//成绩:[0,100]
stus[i].score = (int)(Math.random() * (100 - 0 + 1));
}
//遍历学生数组
for(int i = 0;i <stus.length;i++){
System.out.println(stus[i].info());
}
System.out.println("********************");
//问题一:打印出3年级(state值为3)的学生信息。
for(int i = 0;i <stus.length;i++){
if(stus[i].state == 3){
System.out.println(stus[i].info());
}
}
System.out.println("********************");
//问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
for(int i = 0;i < stus.length - 1;i++){
for(int j = 0;j < stus.length - 1 - i;j++){
if(stus[j].score > stus[j + 1].score){
//如果需要换序,交换的是数组的元素:Student对象!!!
Student temp = stus[j];
stus[j] = stus[j + 1];
stus[j + 1] = temp;
}
}
}
//遍历学生数组
for(int i = 0;i <stus.length;i++){
System.out.println(stus[i].info());
}
}
}
class Student{
int number;//学号
int state;//年级
int score;//成绩
//显示学生信息的方法
public String info(){
return "学号:" + number + ",年级:" + state + ",成绩:" + score;
}
}
5 理解“万事万物皆对象”
1. 在java语言中,我们都将功能、结构等封装到类中,通过类的实例化,来调用具体的功能结构。
-
scanner, String等
-
文件:File
-
网络资源:URL
2. 涉及到java语言与前端Html、后端数据库交互时,前后端在java层面交互时,都体现为类、对象。
4.6 再谈方法
1 方法重载
定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数
类型不同即可。
举例:Arrays中有重载的sort()方法,传入参数类型不一样。
特点:
与权限修饰符、方法体、形参变量名、返回值类型无关,
只看参数列表
,且参数列表必须不同。(参数个数或参数类
型)。调用时,根据方法参数列表的不同来区别。
//以下三个方法构成了重载
public int max(int x, int y){
return x > y ? x : y;
}
public double max(double d1, double d2){
return d1 > d2 ? d1 : d2;
}
public double max(double d1, double d2, double d3){
double max = d1 > d2 ? d1 : d2;
return max > d3 ? max : d3;
}
2 可变个数形参
-
jdk 5.0 新增内容
-
格式:数据类型 ... 变量名
-
传入参数个数可以是任意个
-
可变参数形参的方法与本类中方法名相同,形参不同的方法构成了重载; 与本类中方法名相同,形参类型相同的数组不构成重载
-
可变个数形参只能声明在形参列表末尾,最多只能声明一个
public class Test{
public void show(String s){
//方法1
}
//s:可变个数形参
public void show(String ... s){
//方法2
}
public void show(String[] s){
//注:这个方法会报错
}
}
//调用
Test test = new Test();
test.show("a"); //调用了方法1(若没有方法1,则调用方法2)
test.show("a", "b"); //调用方法2
3 方法参数的值传递机制
-
形参:方法声明时的参数
-
实参:方法调用时实际传给形参的参数值
Java里方法的参数传递方式只有一种:
值传递。 即将实际参数值的副本
(复制品)传入方法内,而参数本身不受影响。
-
形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参
-
形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参
此时原始数据并没有改变。
解决方法:
补充题:
1.判断输出结果
/*
输出其他引用类型时,调用println(Object),输出char[]时,调用println(char[])方法,
这个方法体中写的是遍历的内容
*/
int[] arr = new int[]{1,2,3};
System.out.println(arr); //地址值
char[] arr1 = new char[]{'a','b','c'};
System.out.println(arr1); //abc
4 递归方法
-
递归方法:一个方法体内调用它自身。
-
方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执 行无须循环控制。
-
递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死 循环。
例:计算1-100之间所有数字的和
public class Test {
public static void main(String[] args) {
Test test = new Test();
int sum = test.getSum(100);
System.out.println(sum);
}
public int getSum(int n) {
if(n == 1)
return 1;
else
return n + getSum(n - 1);
}
}
4.7 面向对象特性之一:封装与隐藏
我们程序设计追求“
高内聚,低耦合”。
-
高内聚 :类的内部数据操作细节自己完成,不允许外部干涉。
-
低耦合 :仅对外暴露少量的方法用于使用。
把该隐藏的隐藏起来,该暴露
的暴露出来。这就是封装性的设计思想。
1 问题引入
使用者对类内部定义的属性(对象的成员变量)的直接操作会导致数据的错误、混乱或安全性问题。一些限制条件无法在声明时添加,只能通过方法添加,并且将属性设为私有。
解决方式:信息隐藏,通过get()调用,set()设置。
封装性的体现
-
将类的属性私有化,同时提供公共的(public)方法来获取(getxxx)和设置(setxxx)。
-
一些方法设为private,仅在内部使用,不对外暴露。
-
单例模式
-
...
2 权限修饰符
封装性的体现需要权限修饰符。
4种权限都可以修饰的内部结构:属性,方法,构造器,内部类;修饰类,只能用public, default
总结封装性:
java提供了4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小。
4.8 类的成员之三:构造器(constructor)
1 构造器的特征
-
它具有与类相同的名称
-
它不声明返回值类型。(与声明为void不同)
-
不能被static、final、synchronized、abstract、native修饰,不能有 return语句返回值
2 构造器的作用:
创建对象;给对象进行初始化。
如:Order o = new Order(); Person p = new Person(“Peter”,15);
(创建类的对象:new + 构造器)
说明:
1. 如果没有显式定义类的构造器,系统默认提供一个空参的构造器。
2. 一旦显示的定义了类的构造器后,系统就不再提供默认的空参构造器。
3. 格式:权限修饰符 类名(形参列表){ }
4. 构造器可以创建多个(参数不同即可)。类中定义的多个构造器构成重载。
class Person{
String name;
int age;
public Person() {
}
public Person(String name) {
this.name = name;
}
}
5. 默认构造器的修饰符与所属类的修饰符一致。
6. 父类的构造器不可被子类继承。
3 属性赋值过程
4 拓展:JavaBean
JavaBean是一种Java语言写成的可重用组件。
所谓javaBean,是指符合如下标准的Java类:
-
类是公共的
-
有一个无参的公共的构造器
-
有属性,且有对应的get、set方法
用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以
用Java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP
页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。用
户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。
5 扩展:UML类图
4.9 this关键字
1 this 可以调用类的属性、方法和构造器
2 this修饰属性或方法
this可以理解为:当前对象
-
它在方法内部使用,即这个方法所属对象的引用;
-
它在构造器内部使用,表示该构造器正在初始化的对象。
使用:
-
当在方法内需要用到调用该方法的对象时,就用this。 具体的:我们可以用this来区分属性和局部变量。 比如:this.name = name;
-
通常形况下会省略,特殊情况下,如方法的形参和类属性同名时,我们必须显示的使用 this.变量 的方式,表明此变量是属性,而非形参。
-
使用this访问属性和方法时, 如果在本类中未找到,会从父 类中查找。
3 this修饰构造器
在类使用构造器初始化时,有一些代码多个构造器都需要执行,如果每个构造器中都实现,代码会有些冗余。
解决方式:
在类的构造器中可以使用“this(形参列表)”方式调用本类中其他的构造器。(不能调用自己,也不能形成闭环)
注意:
-
如果一个类中声明了n个构造器,则最多有 n - 1个构造器中使用了 "this(形参列表)"
-
"this(形参列表)"必须声明在类的构造器的首行。
-
在类的一个构造器中,最多只能声明一个"this(形参列表)"
注:eclipse自动生成get, set方法 source -> generate getters and setters
(也可以自动生成构造器)
4.10 package, import关键字
1 package
-
包帮助管理大型软件系统:将功能相近的类划分到同一个包中。比如: MVC的设计模式
-
使用package声明类或者接口所属的包,声明在源文件首行。
-
属于标识符,遵循标识符命名的规范。
-
每一个"."代表一层文件目录。(com.atguigu.java)
-
同一个包下不能命名同名接口和类, 不同包下可以。
补:MVC设计模式
2 import
-
在源文件中,显式的使用import结构导入指定包下的类,接口。
-
声明在包和类的声明之间。
-
导入多个结构可以并列导入或者直接使用“xxx.*;”的方式。(若使用子包的结构,则仍需要显示导入)
-
java.lang包或者本包下定义的类或接口,可以省略导入。
-
import static: 表示导入类或接口的静态结构。
特殊情况:希望使用不同抱下同一名称的类
//至少需要一个类使用全类名的方式调用
import com.package1.Clas;
Clas clas1 = new Clas();
com.package2.Clas clas2 = new com.atjava.test.Account();