前言
学习面向对象内容的三条主线
- Java类及类的成员 (属性、方法、构造器;代码块、内部类)
- 面向对象的三大特征 (封装、继承、多态)
- 其它关键字
一、面向过程与面向对象
1.1 面向过程(POP)与面向对象(OOP)
- 二者都是一种思想,面向对象是相对于面向过程而言的。面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做。面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
- 面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如抽象、分类、继承、聚合、多态等。
1.2 面向对象的三个特征
- 封装
- 继承
- 多态
1.3 面向对象的思想概述
- 程序员从面向过程的执行者转化成了面向对象的指挥者
面向对象分析方法分析问题的思路和步骤:
- 根据问题需要,选择问题所针对的现实世界中的实体。
- 从实体中寻找解决问题相关的属性和功能,这些属性和功能就形成了概念世界中的类。
- 把抽象的实体用计算机语言进行描述,形成计算机世界中类的定义。即借助某种程序语言,把类构造成计算机能够识别和处理的数据结构。
- 将类实例化成计算机世界中的对象。对象是计算机世界中解决问题的最终工具。
1.4 案例
人把大象装进冰箱
一、Java面向对象学习的三条主线:(第4-6章)
1.Java类及类的成员:属性、方法、构造器;代码块、内部类
2.面向对象的三大特征:封装性、继承性、多态性(抽象性)
3.其它关键字:this、super、static、final、abstract、interface、package、import等
*二、“人把大象装进冰箱”
*1.面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做
*
*①把冰箱门打开
*②抬起大象,装进冰箱
*③把冰箱门关闭
*
*2.面向对象:强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
*
*人{
* 打开(冰箱){
* 冰箱.开开();
* }
*
* 抬起(大象){
* 大象.进入(冰箱);
* }
*
* 关闭(冰箱){
* 冰箱.闭合();
* }
*}
*
*冰箱{
* 开开(){}
* 闭合(){}
*}
*
*大象{
* 进入(冰箱){
* }
*}
二、Java语言的基本元素:类和对象
2.1 面向对象的思想概述
- 类:类是对一类事物的描述,是抽象的、概念上的定义
- 对象:对象是实际存在的该类事物的每个个体,因而也称为实例(instance)。
- 可以理解为:类 = 抽象概念的人;对象 = 实实在在的某个人;
- 面向对象程序设计的重点是类的设计
- 设计类:其实就是设计类的成员
2.2 Java类及类的成员
- 现实世界的生物体,大到鲸鱼,小到蚂蚁,都是由最基本的细胞构成的。同理,Java代码世界是由诸多个不同功能的类构成的。
现实生物世界中的细胞又是由什么构成的呢?细胞核、细胞质、… 那么, Java中用类class来描述事物也是如此。常见的类的成员有:
- 属性:对应类中的成员变量
- 行为:对应类中的成员方法
2.3 类的语法格式
修饰符 class 类名 {
属性声明;
方法声明;
}
//说明:修饰符public:类可以被任意访问,类的正文要用{ }括起来
比如:
public class Person{
private int age ; //声明私有变量 age
public void showAge(int i) { //声明方法showAge( )
age = i;
}
}
2.4 创建Java自定义类
步骤:
- 定义类(考虑修饰符、类名)
- 编写类的属性(考虑修饰符、属性类型、属性名、初始化值)
- 编写类的方法(考虑修饰符、返回值类型、方法名、形参等)
三、对象的创建和使用
- 创建对象语法: 类名 对象名 = new 类名();
- 使用“对象名.对象成员”的方式访问对象成员(包括属性和方法)
public class Animal {
public int legs;
public void eat(){
System.out.println(“Eating.”);
}
public viod move(){
System.out.println(“Move.”);
}
}
比如:
public class Zoo{
public static void main(String args[]){
//创建对象
Animal xb=new Animal();
xb.legs=4;//访问属性
System.out.println(xb.legs);
xb.eat();//访问方法
xb.move();//访问方法
}
}
3.1 提 示
类的访问机制:
- 在一个类中的访问机制:类中的方法可以直接访问类中的成员变量。(例外:static方法访问非static,编译不通过。)
- 在不同类中的访问机制:先创建要访问类的对象,再用对象访问类中定义的成员。
3.2 对象的产生
Person p1 = new Person();执行完后的内存状态。其中类定义如下:
class Person{
int age;
void shout(){
System.out.println(“oh,my god! I am ” + age);
}
}
3.3 对象的使用
class PersonTest{
public static void main(String[] args) { //程序运行的内存布局如下图
Person p1 = new Person();
Person p2 =new Person();
p1.age = -30;
p1.shout();
p2.shout();
}
}
3.3 对象的生命周期
3.4 对象的内存解析
堆(Heap),此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在
Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。通常所说的栈(Stack),是指虚拟机栈。虚拟机栈用于存储局部变量等。局部变量表存放了编译期可知长度的各种基本数据类型(boolean、byte、 char 、 short 、 int 、 float 、 long 、 double)、对象引用(reference类型, 它不等同于对象本身,是对象在堆内存的首地址)。 方法执行完,自动释放。
方法区(Method Area),用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
局部变量在栈空间中,属性(成员变量)在堆空间中
3.4.1 案例1
package com.atguigu.java;
/*
* 一、设计类,就是设计类的成员
* 属性 = 成员变量 = field = 域、字段
* 方法 = 成员方法 = 函数 = method
*
* 创建类的对象 = 类的实例化 = 实例化类
*
* 二、类和对象的使用(面向对象思想落地的实现)
* 1.创建类、设计类的成员(属性、方法)
* 2.创建类的对象(类的实例化)
* 3.通过“对象.属性”或“对象.方法”调用对象的结构
*
* 三、如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的)
* 意味着:如果我们修改一个对象的属性a,则不影响另外一个对象属性a的值
* */
//测试类
public class PersonTest {
public static void main(String[] args){
//2.创建Person类的对象
Person p1 = new Person();//类的实例化
//Scanner scanner = new Scanner(System.in);
//调用对象的结构:属性、方法
//调用属性:“对象.属性”
p1.name = "Tom";
p1.isMale = true;
System.out.println(p1.name);
//调用方法:“对象.方法”
p1.eat();
p1.sleep();
p1.talk("chinese");
//*************************
Person p2 = new Person();//开辟空间
System.out.println(p2.name);//null
System.out.println(p2.isMale);//false
//*************************
//p1变量保存的对象地址值赋给p3,导致p1和p3指向堆空间的同一个对象实体
Person p3 = p1;//相当于p1的快捷方式
System.out.println(p3.name);//Tom
p3.age = 10;
System.out.println(p1.age);//10
}
}
//1.创建类、设计类的成员(属性、方法)
class Person{
//属性
String name;//引用类型,默认为null
int age = 1;
boolean isMale;//默认为false
//方法
public void eat(){
System.out.println("人可以吃饭");
}
public void sleep(){
System.out.println("人可以睡觉");
}
public void talk(String language){
System.out.println("人可以说话,使用的是:" + language);//连接符
}
}
3.4.2 案例2
3.5 匿名对象
package com.atguigu.java;
/*
* 一、理解”万事万物皆对象“
* 1.在jav语言范畴中,我们都将功能、结构等封装到类中,通过类的实例化,来调用具体的功能结构
* >Scanner,String等
* >文件:File
* >网络资源:URL
* 2.涉及到Java语言与前端Html、后端数据库交互时,前后端的结构在Java层面交互时,都体现为类、对象
*
* 二、内存解析的说明
* 1.引用类型的变量,只可能存储两类值:null 或 地址值(包含变量的类型)
*
* 三、匿名对象的使用
* 1.理解:我们创建的对象,没有显示的赋给一个变量名,即为匿名对象
* 2.特征:匿名对象只能调用一次
* 3.使用
*/
public class InstanceTest {
public static void main(String[] args) {
Phone p = new Phone();
System.out.println(p);//地址值
p.sendEmail();
p.play();
//匿名对象
/*new Phone().sendEmail();
new Phone().play();*/
new Phone().price = 1999;
new Phone().showPrice();//0.0
//****************************
PhoneMall mall = new PhoneMall();
// mall.show(p);
//匿名对象的使用
mall.show(new Phone());//实参的值传递给形参
}
}
class PhoneMall{
public void show(Phone phone){
phone.sendEmail();
phone.play();
}
}
class Phone{
double price;
public void sendEmail(){
System.out.println("发送邮件");
}
public void play(){
System.out.println("玩游戏");
}
public void showPrice(){
System.out.println("价格" + price);
}
}
四、类的成员之一:属性(field)
package com.atguigu.java;
/*
* 类中属性的使用
*
* 属性(成员变量) VS 局部变量
* 1.相同点
* 1.1 定义变量的格式: 数据类型 变量名 = 变量值
* 1.2先声明,后使用
* 1.3变量都有其对应的作用域
*
* 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)
* 局部变量:加载到栈空间
*
* */
public class UserTest {
public static void main(){
User u1 = new User();
System.out.println(u1.name);
System.out.println(u1.age);
System.out.println(u1.isMale);
u1.talk("日语");
}
}
class User{
//属性(或成员变量)
String name;
int age;
boolean isMale;
public void talk(String language){//;/language:形参
System.out.println("我们使用" + language + "进行交流");
}
public void eat(){
String food = "烙饼";//局部变量
System.out.println("北方人喜欢吃: " + food);
}
}
五、类的成员之二: 方法(method)
package com.atguigu.java;
/*
* 类中方法的声明和使用
*
* 方法:描述类应该具有的功能
*比如:Math类:sqrt()\randow()\...
* Scanner类:nextXxx()...
* Arrays类:sort()\binarySearch()\toString()\equals()
*1.举例:
*public void eat(){}
*public void sleep(int hour){}
*public String getName(){}
*public String getNation(String nation){}
*
*2.方法的声明:权限修饰符 返回值类型 方法名(形参列表){
* 方法体
*}
*注意:static、final、abstract 来修饰的方法,后面再讲
*
*3. 说明:
* 3.1关于权限修饰符:
* Java规定的四种权限修饰符:private、public、缺省、protected-->封装性细说
* 3.2返回值类型:有返回值 VS 没有返回值
* 3.2.1如果方法有返回值,则必须在方法声明时,指定返回值的类型。同时,方法中,需要使用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.return关键字的使用:
* 1.使用范围:使用在方法体中
* 2.作用:①结束方法
* ②针对于有返回值的方法,使用“return 数据”方法,返回所要的数据
* 注意点:return关键字后面不可以声明执行语句
*
*5.方法的使用中,可以调用当前类的属性或方法
* 特殊的:方法A中又调用了方法A:递归方法
* 方法中,不可以定义方法
*/
public class CustomerTest {
public static void main(String args){
Customer cust1 = new Customer();
cust1.eat();
}
}
class Customer{
//属性
String name;
int age;
boolean isMale;
//方法
public void eat(){
System.out.println("客户吃饭");
}
public void sleep(int hour){
System.out.println("休息了" + hour + "个小时");
}
public String getName(){
if(age > 18){
return name;
}else{
return "Tom";
}
}
public String getNation(String nation){
String info = "我的国籍是:" + nation;
reurn info;
}
}
练习1:
package com.atguigu.exer;
/*
* 要求:
* (1)创建Person类的对象,设置该对象的name、age和sex属性,调用study方法,
* 输出字符串“studying”,调用showAge()方法显示age值,调用addAge()方法给对象的age属性值增加2岁。
* (2)创建第二个对象,执行上述操作,体会同一个类的不同对象之间的关系。
*/
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.name = "Tom";
p1.age = 18;
p1.sex = 1;
p1.study();
p1.showAge();//alt+左 进去
int newAge = p1.addAge(2);
System.out.println(p1.name + "的新年龄为:" + newAge);
System.out.println(p1.age);//20
//*********************************
Person p2 = new Person();
p2.showAge();//0
p2.addAge(10);
p2.showAge();//10
}
}
Person类
package com.atguigu.exer;
public class Person {
String name;
int age;
/**
* sex:1表明是男性
* sex:0表明是女性
*/
int sex;
public void study(){
System.out.println("studying");
}
public void showAge(){
System.out.println("age" + age);
}
public int addAge(int i){
age += i;
return age;
}
}
练习2:利用面向对象的编程方法,设计类Circle计算圆的面积
CircleTest类
package com.atguigu.exer;
/*
* 2.利用面向对象的编程方法,设计类Circle计算圆的面积。
*
*/
//测试类
public class CircleTest {
//程序的入口
public static void main(String[] args) {
Circle c1 = new Circle();
c1.radius = 2.1;
/*//对应方式一:
double area = c1.findArea();
System.out.println(area);*/
//对应方式二:
c1.findArea();
}
}
//圆
class Circle{
//属性/成员变量
double radius;
//求圆的面积
//方式一:
/*public double findArea(){
double area = 3.14 * radius * radius;
return area;
}*/
//方式二:
public void findArea(){
double area = 3.14 * radius * radius;
System.out.println("面积为:" + area);
}
}
练习3
package com.atguigu.exer;
/*
* 3.1 编写程序,声明一个method方法,在方法中打印一个10*8 的*型矩形, 在main方法中调用该方法。 3.2 修改上一个程序,在method方法中,除打印一个10*8的*型矩形外,再
* 计算该矩形的面积,并将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印。
* 3.3 修改上一个程序,在method方法提供m和n两个参数,方法中打印一个
* m*n的*型矩形,并计算该矩形的面积, 将其作为方法返回值。在main方法
* 中调用该方法,接收返回的面积值并打印.
* */
public class Exer3Test {
public static void main(String[] args) {
Exer3Test test = new Exer3Test();
//3.1测试
// test.method();
//3.2测试
/*int area = test.method();
System.out.println(area);*/
//3.3测试
int area = test.method(2,2);
System.out.println(area);
}
//3.1
/*public void method(){
for(int i = 0;i < 10;i++){
for(int j = 0;j < 8;j++){
System.out.print("* ");
}
System.out.println();
}
}*/
//3.2
/*public int method(){
for(int i = 0;i < 10;i++){
for(int j = 0;j < 8;j++){
System.out.print("* ");
}
System.out.println();
}
return 10 * 8;
}*/
//3.3
public int method(int m,int n){
for(int i = 0;i < m;i++){
for(int j = 0;j < n;j++){
System.out.print("* ");
}
System.out.println();
}
return m * n;
}
}
练习4
package com.atguigu.exer;
/*4. 对象数组题目:
定义类Student,包含三个属性:学号number(int),年级state(int),成绩score(int)。
创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
问题一:打印出3年级(state值为3)的学生信息。
问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
提示:
1) 生成随机数:Math.random(),返回值类型double;
2) 四舍五入取整:Math.round(double d),返回值类型long。
*/
public class StudentTest {
public static void main(String[] args) {
//声明Student类型的数组,String[] arr = new String[20];
Student[] stus = new Student[20];//动态
for(int i = 0;i < stus.length;i++){
//给数组元素赋值
stus[i] = new 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) + 0);
}
//遍历学生数组
for(int i = 0;i < stus.length;i++){
/*System.out.println(stus[i].number + "," + stus[i].state
+ "," + stus[i].score);*/
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++){
//冒泡的比较次数就是比数组长度少一,所以减1
for(int j = 0; j < stus.length - i - 1;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:对练习4的优化
package com.atguigu.exer;
/*4. 对象数组题目:
定义类Student,包含三个属性:学号number(int),年级state(int),成绩score(int)。
创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
问题一:打印出3年级(state值为3)的学生信息。
问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
提示:
1) 生成随机数:Math.random(),返回值类型double;
2) 四舍五入取整:Math.round(double d),返回值类型long。
此代码是对StudentTest.java的改进:将操作数组的功能封装到方法中
*/
public class StudentTest1 {
public static void main(String[] args) {
//声明Student类型的数组,String[] arr = new String[20];
Student1[] stus = new Student1[20];//动态
for(int i = 0;i < stus.length;i++){
//给数组元素赋值
stus[i] = new Student1();
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) + 0);
}
StudentTest1 test = new StudentTest1();
//遍历学生数组
test.print(stus);
System.out.println("打印*************************");
//问题一:打印出3年级(state值为3)的学生信息。
test.searchState(stus, 3);
System.out.println("排序*************************");
//问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
test.sort(stus);
//遍历学生数组
test.print(stus);
}
//遍历Student1[]数组的操作
public void print(Student1[] stus){
//遍历学生数组
for(int i = 0;i < stus.length;i++){
System.out.println(stus[i].info());
}
}
/**
* 查找Student数组中指定年级的学生信息
* @param stus 要查找的数组
* @param state 要查找的年级
*/
public void searchState(Student1[] stus,int state){
for(int i = 0;i < stus.length;i++){
if(stus[i].state == state){
System.out.println(stus[i].info());
}
}
}
/**
* 对Student1数组进行冒泡排序
* @param stus
*/
public void sort(Student1[] stus){
for(int i = 0;i < stus.length - 1;i++){
//冒泡的比较次数就是比数组长度少一,所以减1
for(int j = 0; j < stus.length - i - 1;j++){
if(stus[j].score > stus[j + 1].score){
//如果需要换序,交换的是数组的元素,Student对象!!!
Student1 temp = stus[j];
stus[j] = stus[j + 1];
stus[j + 1] = temp;
}
}
}
}
}
class Student1{
int number;//学号
int state;//年级
int score;//成绩
//显示学生信息的方法
public String info(){
return "学号:" + number + ",年级:" + state + ",成绩:" + score;
}
}