二、Java面向对象编程(上)

  • 学习面对对象内容的三条主线:
    1.Java类及类的成员
    2.面向对象的三大特征
    3.其它关键字

1.面向过程与面向对象

2.Java基本元素:类与对象

2-1 面向对象的思想概述

  • 类(Class)对象(Object)是面向对象的核心概念。
    • 类是对一类事物的描述,是抽象的、概念上的定义
    • 对象是实际存在的该类事物的每个个体,因而也称为实例(instance)
  • 万事万物皆对象

在这里插入图片描述

  • 可以理解为:类 = 抽象概念的人;对象 = 实实在在的某个人

  • 面向对象程序设计的重点是类的设计

  • 类的设计,其实就是类的成员设计

2-2 类的语法格式

修饰符 class 类名 {
属性声明;
方法声明;
}
说明:修饰符public:类可以被任意访问
类的正文要用{ }括起来

2-3 创建Java自定义类

步骤:

  1. 定义类(考虑修饰符、类名)
  2. 编写类的属性(考虑修饰符、属性类型、属性名、初始化值)
  3. 编写类的方法(考虑修饰符、返回值类型、方法名、形参等)

练习

定义Person、Animal、ClassRoom、Zoo等类,加以体会。

3.对象的创建和使用(类的实例化)

创建对象语法: 类名 对象名 = new 类名();
使用“对象名.对象成员”的方式访问对象成员(包括属性和方法)

代码举例:

说明:如果创建了一个类的多个对象,对于类中定义的属性,每个对象都拥有各自的一套副本,且互不干扰。

练习:

在这里插入图片描述
类的访问机制
在一个类中的访问机制:类中的方法可以直接访问类中的成员变量。
(例外:static方法访问非static,编译不通过。)
在不同类中的访问机制:先创建要访问类的对象,再用对象访问类中
定义的成员。

匿名对象:

  • 我们也可以不定义对象的句柄,而直接调用这个对象的方法。这 样的对象叫做匿名对象。
    • 如:new Person().shout();
  • 使用情况
    • 如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。
    • 我们经常将匿名对象作为实参传递给一个方法调用。

4.类的成员之一:属性(field)

4-1 语法格式

修饰符 数据类型 属性名 = 初始化值 ;

  • 说明1: 修饰符
    • 常用的权限修饰符有:private、缺省、protected、public
    • 其他修饰符:static、final (暂不考虑)
  • 说明2:数据类型
    • 任何基本数据类型(如int、Boolean) 或 任何引用数据类型。
  • 说明3:属性名
    • 属于标识符,符合命名规则和规范即可。
//代码举例
public class Person{
    
    
private int age; //声明private变量 age
public String name = “Lila”; //声明public变量 name
}

4-2 变量的分类

方法体外,类体内声明的变量称为成员变量
方法体内部声明的变量称为局部变量
在这里插入图片描述
注意:二者在初始化值方面的异同:
同:都有生命周期
异:局部变量除形参外,均需显式初始化。

成员变量与局部变量的区别如下表:

成员变量 局部变量
声明的位置 直接声明在类中 方法形参或内部、代码块内、构造器内等
修饰符 private、public、static、final等 不能用权限修饰符修饰,可以用final修饰
初始化值 有默认初始化值 没有默认初始化值,必须显式赋值,方可使用
内存加载位置 堆空间 或 静态域内 栈空间

4-3 对象属性的默认初始化赋值

当一个对象被创建时,会对其中各种类型的成员变量自动进行初始化赋值。除了
基本数据类型之外的变量类型都是引用类型

成员变量类型 初始值
byte 0
short 0
int 0
long 0L
float 0.0F
double 0.0
char 0或写成: ‘\u0000’(null)
boolean false
引用类型 null

5.类的成员之二:方法

5-1 方法的定义

什么是方法(method、函数):

  • 方法是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中也称为函数或过程。
  • 将功能封装为方法的目的是,可以实现代码重用,简化代码
  • Java里的方法不能独立存在,所有的方法必须定义在类里。
//代码示例
public class Person{
    
    
	private int age;
	public int getAge() {
    
     //声明方法getAge()
		return age;
	}
	public void setAge(int i) {
    
     //声明方法setAge
		age = i; //将参数i的值赋给类的成员变量age
	}
}

5-2 方法的声明格式

修饰符 返回值类型 方法名(参数类型 形参1, 参数类型 形参2,.){
	方法体程序代码
	return 返回值;

其中:

  • 修饰符:public,缺省,private, protected等
  • 返回值类型:
    • 没有返回值:void。
    • 有返回值,声明出返回值的类型。与方法体中“return 返回值”搭配使用
  • 方法名:属于标识符,命名时遵循标识符命名规则和规范,“见名知意”
  • 形参列表:可以包含零个,一个或多个参数。多个参数时,中间用“,”隔开
  • 返回值:方法在执行完毕后返还给调用它的程序的数据。

问题:如何理解方法返回值类型为void的情况 ?

注 意:

  • 方法被调用一次,就会执行一次
  • 没有具体返回值的情况,返回值类型用关键字void表示,那么方法体中可以不必使用return语句。如果使用,仅用来结束方法。
  • 定义方法时,方法的结果应该返回给调用者,交由调用者处理。
  • 方法中只能调用方法或属性,不可以在方法内部定义方法。

5-3 方法的重载(overload)

1、概念:
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
2、特点:
与返回值类型无关,只看参数列表,且参数列表必须不同。(参数个数或参数类型)。调用时,根据方法参数列表的不同来区别。
3、重载示例

//返回两个整数的和
int add(int x,int y){
    
    return x+y;}
//返回三个整数的和
int add(int x,int y,int z){
    
    return x+y+z;}
//返回两个小数的和
double add(double x,double y){
    
    return x+y;}

5-4 方法参数的值传递机制

方法,必须由其所在类或对象调用才有意义。若方法含有参数:

  1. 形参:方法声明时的参数
  2. 实参:方法调用时实际传给形参的参数值

问题:Java的实参值如何传入方法呢?
Java里方法的参数传递方式只有一种:值传递。 即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响。

  • 形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参
public static void main(String[] args) {
    
    
	int x = 5;
	System.out.println("修改之前x = " + x);// 5
	// x是实参
	change(x);
	System.out.println("修改之后x = " + x);// 5
}
public static void change(int x) {
    
    
	System.out.println("change:修改之前x = " + x);
	x = 3;
	System.out.println("change:修改之后x = " + x);
}
  • 形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参
public static void main(String[] args) {
    
    
	Person obj = new Person();
	obj.age = 5;
	System.out.println("修改之前age = " + obj.age);// 5
	// x是实参
	change(obj);
	System.out.println("修改之后age = " + obj.age);// 3
}
public static void change(Person obj) {
    
    
	System.out.println("change:修改之前age = " + obj.age);
	obj.age = 3;
	System.out.println("change:修改之后age = " + obj.age);
}
其中Person类定义为:
class Person{
    
    
int age;
}

5-3 递归(recursion)方法

递归方法:一个方法体内调用它自身。

  • 方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
  • 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
//计算1-100之间所有自然数的和
public int sum(int num){
    
    
	if(num == 1){
    
    
		return 1;
	}else{
    
    
		return num + sum(num - 1);
	}
}

5-5 练习

方法的练习

1.在这里插入图片描述
2.利用面向对象的编程方法,设计类Circle计算圆的面积。
3.编写程序,声明一个method方法,在方法中打印一个10 * 8 的型矩形,在main方法中调用该方法。
4.修改上一个程序,在method方法中,除打印一个10 * 8 的
型矩形外,再计算该矩形的面积,并将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印。
5. 修改上一个程序,在method方法提供m和n两个参数,方法中打印一个m * n的*型矩形,并计算该矩形的面积, 将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印。
6. 对象数组题目:
定义类Student,包含三个属性:学号number(int),年级state(int),成绩
score(int)。 创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
问题一:打印出3年级(state值为3)的学生信息。
问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
提示:

  1. 生成随机数:Math.random(),返回值类型double;
  2. 四舍五入取整:Math.round(double d),返回值类型long。

7.声明一个日期类型MyDate:有属性:年year,月month,日day。创建2个日期对象,分别赋值为:你的出生日期,你对象的出生日期,并显示信息。

方法重载的练习

1、编写程序,定义三个重载方法并调用。方法名为mOL。

  • 三个方法分别接收一个int参数、两个int参数、一个字符串参数。分别执行平方运算并输出结果,相乘并输出结果,输出字符串信息。
  • 在主类的main ()方法中分别用参数区别调用三个方法。

2、定义三个重载方法max(),第一个方法求两个int值中的最大值,第二个方法求两个double值中的最大值,第三个方法求三个double值中的最大值,并分别调用三个方法。

将对象作为参数传递给方法

(1)定义一个Circle类,包含一个double型的radius属性代表圆的半径,一个findArea()方法返回圆的面积。
(2)定义一个类PassObject,在类中定义一个方法printAreas(),该方法的定义如下:
public void printAreas(Circle c, int time)
在printAreas方法中打印输出1到time之间的每个整数半径值,以及对应的面积。
例如,times为5,则输出半径1,2,3,4,5,以及对应的圆面积。

递归的练习

请用Java写出递归求阶乘(n!)的算法

  • 已知有一个数列:f(0) = 1,f(1) = 4,f(n+2)=2*f(n+1) +
    f(n),其中n是大于0的整数,求f(10)的值。
  • 已知一个数列:f(20) = 1,f(21) = 4,f(n+2) =
    2*f(n+1)+f(n),其中n是大于0的整数,求f(10)的值。
  • 输入一个数据n,计算斐波那契数列(Fibonacci)的第n个值1 1 2 3 5 8 13 21 34 55
    规律:一个数等于前两个数之和
    要求:计算斐波那契数列(Fibonacci)的第n个值,并将整个数列打印出来

6.OOP特征一:封装性

6-1 为什么有封装性

  • 为什么需要封装?封装的作用和含义?
    • 我要用洗衣机,只需要按一下开关和洗涤模式就可以了。有必要了解洗衣机内部的结构吗?有必要碰电动机吗?我要开车,…
  • 我们程序设计追求“高内聚,低耦合”。
    • 高内聚 :类的内部数据操作细节自己完成,不允许外部干涉;
    • 低耦合 :仅对外暴露少量的方法用于使用。

隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想

6-2 信息的封装

  • Java中通过将数据声明为私有的(private),再提供公共的(public)方法:getXxx()和setXxx()实现对该属性的操作,以实现下述目的:
    • 隐藏一个类中不需要对外提供的实现细节;
    • 使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑,限制对属性的不合理操作;
    • 便于修改,增强代码的可维护性;
class Animal {
    
    
	private int legs;// 将属性legs定义为private,只能被Animal类内部访问
	public void setLegs(int i) {
    
     // 在这里定义方法 eat() 和 move()
		if (i != 0 && i != 2 && i != 4) {
    
    
			System.out.println("Wrong number of legs!");
			return;
		}
		legs = i;
	}
	public int getLegs() {
    
    
		return legs;
	}
}
public class Zoo {
    
    
	public static void main(String args[]) {
    
    
		Animal xb = new Animal();
		xb.setLegs(4); // xb.setLegs(-1000);
		//xb.legs = -1000; // 非法
		System.out.println(xb.getLegs());
	}
}

6-3 四种访问权限修饰符

Java权限修饰符public、protected、(缺省)、private置于类的成员定义前,用来限定对象对该类成员的访问权限。

修饰符 类内部 同一个包 不同包的子类 同一个工程
private
(缺省)
protected
public

对于class的权限修饰只可以用public和default(缺省)。

  • public类可以在任意地方被访问。
  • default类只可以被同一个包内部的类访问。

封装性的练习

创建程序,在其中定义两个类:Person和PersonTest类。定义如下:

  • 用setAge()设置人的合法年龄(0~130),用getAge()返回人的年龄。在 PersonTest 类 中实例化 Person类的对象 b , 调 用 setAge() 和getAge()方法,体会Java的封装性。

7.类的成员之三:构造器(构造方法)

7-1 构造器的定义

  • 构造器的特征
    • 它具有与类相同的名称
    • 它不声明返回值类型。(与声明为void不同)
    • 不能被static、final、synchronized、abstract、native修饰,不能有 return语句返回值
  • 构造器的作用:创建对象;给对象进行初始化

7-2 构造器语法

语法格式:
	修饰符 类名 (参数列表) {
		初始化语句;
	} 
public class Animal {
    
    
	private int legs;
	// 构造器
	public Animal() {
    
    
		legs = 4;
	}
	public void setLegs(int i) {
    
    
		legs = i;
	}
	public int getLegs() {
    
    
		return legs;
	}
}

7-3 构造器分类

根据参数不同,构造器可以分为如下两类:

  1. 隐式无参构造器(系统默认提供)
  2. 显式定义一个或多个构造器(无参、有参)

7-4 构造器注意事例

  1. Java语言中,每个类都至少有一个构造器
  2. 默认构造器的修饰符与所属类的修饰符一致
  3. 一旦显式定义了构造器,则系统不再提供默认构造器
  4. 一个类可以创建多个重载的构造器
  5. 父类的构造器不可被子类继承

8.关键字:this

8-1 this的定义

  • 在Java中,this关键字比较难理解,它的作用和其词义很接近。
    • 它在方法内部使用,即这个方法所属对象的引用;
    • 它在构造器内部使用,表示该构造器正在初始化的对象。
  • this 可以调用类的属性、方法和构造器
  • 什么时候使用this关键字呢?
    • 当在方法内需要用到调用该方法的对象时,就用this。
      • 具体的:我们可以用this来区分属性和局部变量。
      • 比如:this.name = name;
//使用this调用本类的构造器
class Person{
    
     // 定义Person类
	private String name ;
	private int age ;
	public Person(){
    
     // 无参构造器
		System.out.println("新对象实例化") ;
	}
	public Person(String name){
    
    
		this(); // 调用本类中的无参构造器	
		this.name = name ;
	}
	public Person(String name,int age){
    
    
		this(name) ; // 调用有一个参数的构造器
		this.age = age;
	}
	public String getInfo(){
    
    
		return "姓名:" + name + ",年龄:" + age ;
	}
}

注意:

  • 可以在类的构造器中使用"this(形参列表)"的方式,调用本类中重载的其他的构造器!
  • 明确:构造器中不能通过"this(形参列表)"的方式调用自身构造器
  • 如果一个类中声明了n个构造器,则最多有 n - 1个构造器中使用了"this(形参列表)"
  • "this(形参列表)"必须声明在类的构造器的首行
  • 在类的一个构造器中,最多只能声明一个"this(形参列表)"

9.关键字:package、import

9-1 package的定义

  • package语句作为Java源文件的第一条语句,指明该文件中定义的类所在的包。(若缺省该语句,则指定为无名包)。它的格式为:
    • package 顶层包名.子包名 ;

举例:

// 路径:pack1\pack2\PackageTest.java
package pack1.pack2; //指定类PackageTest属于包pack1.pack2

public class PackageTest{
    
    
	public void display(){
    
    
		System.out.println("in method display()");
	}
}
  • 包对应于文件系统的目录,package语句中,用 “.” 来指明包(目录)的层次;
  • 包通常用小写单词标识。通常使用所在公司域名的倒置:com.hunau.xxx

9-2 package的作用

  • 包的作用:
    • 包帮助管理大型软件系统:将功能相近的类划分到同一个包中。比如:MVC的设计模式
    • 包可以包含类和子包,划分项目层次,便于管理
    • 解决类命名冲突的问题
    • 控制访问权限

9-3 import的定义

  • 为使用定义在不同包中的Java类,需用import语句来引入指定包层次下所需要的类或全部类(.*)。import语句告诉编译器到哪里去寻找类。
  • 语法格式:
    • import 包名. 类名;
  • 应用举例:
import pack1.pack2.Test; //import pack1.pack2.*;表示引入pack1.pack2包中的所有结构
public class PackTest{
    
    
	public static void main(String args[]){
    
    
		Test t = new Test(); //Test类在pack1.pack2包中定义
		t.display();
	}
}

9-4 import注意事例

  1. 在源文件中使用import显式的导入指定包下的类或接口
  2. 声明在包的声明和类的声明之间。
  3. 如果需要导入多个类或接口,那么就并列显式多个import语句即可
  4. 举例:可以使用java.util.*的方式,一次性导入util包下所有的类或接口。(影响效率不推荐)
  5. 如果导入的类或接口是java.lang包下的,或者是当前包下的,则可以省略此import语句。
  6. 如果在代码中使用不同包下的同名的类。那么就需要使用类的全类名的方式指明调用的是哪个类。
  7. 如果已经导入java.a包下的类。那么如果需要使用a包的子包下的类的话,仍然需要导入。
  8. import static组合的使用:调用指定类或接口下的静态的属性或方法

猜你喜欢

转载自blog.csdn.net/qq_45830383/article/details/110086438
今日推荐