面向对象
概述
面向对象学习的主线
1.Java类及类的成员
- 属性
- 方法
- 构造器
- 代码块
- 内部类
2.面向对象的三大特征
- 封装性
- 继承性
- 多态性
- 抽象性 (若提起三大特性,则前三个,若四大特性,则再加一抽象性)
3.其他关键字
- this
- super
- static
- final
- abstract
- interface
- package
- import
面向过程和面向对象的对比
- 面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做。
- 面向对象:强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
面向对象的两个要素
- 类 (对一类事物的描述,是抽象的、概念上的定义)
- 面向对象程序设计的重点是类的设计
- 设计类,就是设计类的成员。
- 对象 (是实际存在的该类事物的每个个体,因而也称为实例)
类的创建和使用
设计类
- 属性 = 成员变量 = 字段 = field
- 方法 = 成员方法 = 函数 = method
- 暂略
类和对象的使用
- 创建类,设计类的成员
- 创建类的对象
- 通过对象.属性,对象.方法 调用对象的结构
//创建类,设计类的成员
public class Person{
//属性1
String name;
//属性2,并赋值为1
int age = 1;
// 方法1
public void eat(){
System.out.println("吃饭中);
}
// 方法2
public int getage(){
System.out.println("我的年龄是" + age);
}
}
public class PersonTest {
public static void main(String[] args) {
//2. 创建Person类的对象
Person p1 = new Person();
//3.1 调用属性 对象.属性
p1.name = "Tom";
//3.2 调用方法 对象.方法
p1.eat();
}
}
同类多对象的独立性(非static)
如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的)
public class PersonTest {
public static void main(String[] args) {
//创建p1对象
Person p1 = new Person();
//修改p1对象name属性
p1.name = "Tom";
//再新建一个p2新对象
Person p2 = new Person();
//修改p2对象name属性
p2.name = "Jack";
// 同时输出两对象名字
System.out.println(p1.name);//Tom
System.out.println(p2.name);//Jack
}
}
也就是修改一个对象的属性值a,则不影响另一个对象属性a的值
对象的内存解析
Person p1 = new Person();
p1.name = "Tom";
Person p2 = new Person();
p2.name = "Jack";
System.out.println(p1.name);//Tom
System.out.println(p2.name);//Jack
- 语句一,首先在堆空间中 new 出一个类对象,并在栈空间中声明一个临时变量p1,将类对象的首地址值赋值给临时变量p1,此时p1 指针 指向 类对象。 同时在类对象中完成属性值的初始化(name值为null)
- 语句二,通过p1指针找到对应的类变量,然后找到对应的name属性,并赋值为Tom
- 语句三,在堆空间中再次 new 出一个类对象,并在栈空间中声明一个临时变量p2,将类对象的首地址值赋值给临时变量p2,此时p2 指针 指向 类对象。 同时在类对象中完成属性值的初始化(name值为null)
- 语句四,通过p2指针找到对应的类变量,然后找到对应的name属性,并赋值为Jack
- 通过调用println方法,两个对象的属性值分别输出为 Tom和Jack
- main方法执行过后,局部变量p2先出栈,此时指针失效,p2的类对象无指针指向,引用次数为0,被垃圾回收。然后p1出栈,同理p1类对象也被回收。
Person p1 = new Person();
p1.name = "Tom";
Person p2 = p1;
p2.name = "Jack";
System.out.println(p1.name);//Jack
System.out.println(p2.name);//Jack
- 语句一,同情况一
- 语句二,同情况一
- 语句三,在栈空间中声明局部变量p2,同时将p1的首地址值赋值给p2 (此时p1和p2的指针指向同一个地址)
- 语句四,同情况一
- 通过调用println方法,发现p1和p2 输出都为Jack,其原因是因为它们引用了同一个对象
- main方法执行过后,局部变量p2先出栈,此时指针失效,p2的类对象引用次数减一,但不为0 ,暂时不被垃圾回收。然后p1出栈,此时类对象引用次数为0,被回收。
属性和局部变量的对比
相同点
- 定义变量的格式:数据类型 变量名 = 变量值
- 先声明,后使用
- 变量都有其对应的作用域
不同点
-
在类中声明的位置的不同
- 类的属性:直接定义在类的 { } 中
- 局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量
-
默认初始化值的情况:
- 类的属性:根据类,都有默认初始化值
- 整形(byte,short,int long): 0
- 浮点型(float,double):0.0
- 字符型(char):0–> ‘\u0000’
- 布尔型 (boolean):false
- 引用数据类型(类,数组,接口):null
- 局部变量:没有默认初始化值
- 调用局部变量之前,一定要显示赋值
- 注: 形参在调用时,赋值即可
- 类的属性:根据类,都有默认初始化值
-
关于权限修饰符的不同
- 类的属性:可以使用权限修饰符 (常用的修饰符:private、public、缺省、protected)
- 局部变量:不可以使用修饰符
-
在内存中加载的位置:
- 类的属性:加载到堆空间中 (非static)
- 局部变量:加载到栈空间
类中方法的使用和声明
举例
public void eat(){
} //无参数无返回
public void sleep(int hour){
} //有参数无返回
public String getName(){
} //无参数有返回
public String getNation(String nation){
} //有参数有返回
方法的声明
权限修饰符 返回值类型 方法名(形参列表){
方法体
}
-
权限修饰符
Java规定的4种权限修饰符:private、public、缺省、protected
-
返回值类型
- 若方法中有返回值,则必须在方法声明时,指定返回值类型,同时,方法中必须 return 返回指定类型的变量或常量
- 若方法中没有返回值,则使用 void 来表示。若无返回值,return只能这样 “return;” 使用,表示结束此方法
- 根据需求和经验来判断是否该有返回值
-
方法名
属于标识符,遵循标识符的规则和规范,并且要见名知意
-
形参列表 (可以声明 0 , 1,多个形参)
- 格式: 数据类型1 形参1,数据类型2 形参2,…
- 根据需求和经验来判断是否该有形参
-
方法体
具体的功能代码
return关键字的使用
- 使用范围:方法体中
- 作用
- 结束方法
- 返回需要返回的数据(同时结束方法)
- return关键字后面不可以声明执行语句。
方法和属性的调用
在方法中可以调用当前类的属性和方法
方法又调用方法本身,称递归
方法中不可以定义方法
练习题
一:Person
要求:
(1)创建Person类的对象,设置该对象的name、age和sex属性,调用study方法,
输出字符串“studying”,调用showAge()方法显示age值,
调用addAge()方法给对象的age属性值增加2岁。
(2)创建第二个对象,执行上述操作,体会同一个类的不同对象之间的关系。
public class Person {
String name;
int age;
/**
* sex:0 男
* sex:1 女
*/
int sex;
//学习
public void study(){
System.out.println("studying");
}
//显示年龄
public void showAge(){
System.out.println("年龄是" + age);
}
//增加年龄
public void addAge(int a){
age += a;
}
}
public class PersonTest {
public static void main(String[] args) {
//创建p1对象
Person p1 = new Person();
//进行学习
p1.study();
//显示年龄
p1.showAge();
//添加年龄
p1.addAge(5);
//显示年龄
p1.showAge();
//创建p2对象
Person p2 = new Person();
//修改p2年龄
p2.age = 10;
//同时显示两对象年龄
p1.showAge();
p2.showAge();
}
}
二 : Circle
利用面向对象的编程方法,设计类Circle计算圆的面积。
public class Circle {
double radius;
public double getArea(){
return (Math.PI * radius * radius);
}
public void showArea(){
System.out.println("半径为"+radius+"的圆的面积是 " + getArea() );
}
}
public class CircleTest {
public static void main(String[] args) {
Circle c1 = new Circle();
c1.radius = 2.1;
c1.showArea();
c1.radius = 4.5;
c1.showArea();
}
}
三 : Shape
1 编写程序,声明一个method方法,在方法中打印一个10*8 的*型矩形,在main方法中调用该方法。
2 修改上一个程序,在method方法中,除打印一个10*8的*型矩形外,再计算该矩形的面积,
并将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印。
3 修改上一个程序,在method方法提供m和n两个参数,方法中打印一个m*n的*型矩形,并计算该矩形的面积, 将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印。
public class Shape {
//打印10*8的矩阵
public void tenEight(){
for (int i = 1;i <= 10; i++){
for (int j = 1;j <= 8; j++){
System.out.print("*");
}
System.out.println("");
}
}
//打印m*n的矩阵,并返回面积
public int getArea(int m,int n){
int area = m * n;
for (int i = 1;i <= m; i++){
for (int j = 1;j <= n; j++){
System.out.print("*");
}
System.out.println("");
}
return area;
}
}
public class ShapeTest {
public static void main(String[] args) {
Shape s1 = new Shape();
s1.tenEight();
int area = s1.getArea(2,3);
System.out.println("面积是:"+area);
}
}
四 : Student
定义类Student,包含三个属性:学号number(int),年级state(int),成绩score(int)。
创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
问题一:打印出3年级(state值为3)的学生信息。
问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
public class Student {
//定义属性
int number;
int state;
int score;
//显示信息
public void showData(){
System.out.print("学号:" +number);
System.out.print("年级:" +state);
System.out.print("分数:" +score + "\n");
}
}
public class StudenTest {
public static void main(String[] args) {
//定义学生数组
Student[] students= new Student[20];
//进行赋值
for (int i = 0;i < students.length;i++){
students[i] = new Student();
students[i].number = i;
students[i].state = (int)(Math.random() * (6 - 1 + 1) + 1);//年级范围 1-6
students[i].score = (int)(Math.random() * (100 - 0 + 1) + 0);//分数范围0-100
}
//打印3年级学生信息
for (int i = 0;i < 20;i++){
if (students[i].state == 3){
students[i].showData();
}
}
//根据分数冒泡排序
for (int i = 0;i < students.length;i++){
for (int j = 0;j < students.length - 1;j++){
if(students[j].score < students[j+1].score){
//减缓两个对象的地址值
Student temp = new Student();
temp = students[j+1];
students[j+1] = students[j];
students[j] = temp;
}
}
}
//显示所有学生分数
for (int i = 0;i < 20;i++){
students[i].showData();
}
}
}