目录
四、面向对象(一)
4.1 面向过程与面向对象
面向过程(POP) 与 面向对象(OOP)
- 二者都是一种思想,面向对象是相对于面向过程而言的。面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做。面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
- 面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如抽象、分类、继承、聚合、多态等。
面向对象的三大特征
- 封装 (Encapsulation)
- 继承 (Inheritance)
- 多态 (Polymorphism)
4.2 Java语言的基本元素:类和对象
类(Class)和对象(Object) 是面向对象的核心概念。
- 类是对一类事物的描述,是抽象的、概念上的定义
- 对象是实际存在的该类事物的每个个体,因而也称为实例(instance)。
- 可以理解为:类 = 抽象概念的人;对象 = 实实在在的某个人
- 面向对象程序设计的重点是类的设计
类的设计,其实就是类的成员的设计
类的成员
常见的类的成员有:
- 属 性:对应类中的成员变量
- 行 为:对应类中的成员方法
类的语法格式
修饰符 class 类名 {
属性声明;
方法声明;
}
说明:修饰符public:类可以被任意访问
类的正文要用{ }括起来
举例:
public class Person{
private int age ; //声明私有变量 age
public void showAge(int i) { //声明方法showAge( )
age = i;
}
}
4.3 对象的创建和使用
创建对象语法: 类名 对象名 = new 类名();
使用“对象名.对象成员”的方式访问对象成员(包括属性和方法)。
举例:
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();//访问方法
}
}
练习:编写教师类和学生类,并通过测试类创建对象进行测试
//Student类
package demo04;
public class Student {
private String name;
private int age;
private String major;
private String interests;
public Student(String name, int age, String major, String interests) {
this.name = name;
this.age = age;
this.major = major;
this.interests = interests;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
public String getInterests() {
return interests;
}
public void setInterests(String interests) {
this.interests = interests;
}
public void study(){
System.out.println("学生姓名:"+name);
System.out.println("学生年龄:"+age);
System.out.println("学科:"+major);
System.out.println("兴趣:"+interests);
}
}
//Teacher类
package demo04;
public class Teacher {
private String name;
private int age;
private int teachAge;
private String course;
public Teacher(String name, int age, int teachAge, String course) {
this.name = name;
this.age = age;
this.teachAge = teachAge;
this.course = course;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getTeachAge() {
return teachAge;
}
public void setTeachAge(int teachAge) {
this.teachAge = teachAge;
}
public String getCourse() {
return course;
}
public void setCourse(String course) {
this.course = course;
}
public void teach(){
System.out.println("教师姓名:"+name);
System.out.println("教师年龄:"+age);
System.out.println("教龄:"+teachAge);
System.out.println("教授课程:"+course);
}
}
//test类
package demo04;
public class test {
public static void main(String[] args) {
//教师类创建新对象
Teacher teacher = new Teacher("李老师",35,10,"数学");
teacher.teach();
//学生类创建新对象
Student student = new Student("田天赐",20,"Java","编程");
student.study();
}
}
->运行结果:
教师姓名:李老师
教师年龄:35
教龄:10
教授课程:数学
学生姓名:田天赐
学生年龄:20
学科:Java
兴趣:编程
补充: idea快捷键
"Alt +"系列
Alt + / 快速补全代码 (必须记住,也是最常用的)
Alt + Enter 快速提示完成,在代码可能存在语法问题时,IDEA 会提示使用该快捷键可以快速自动修正(功能非常强大,最常使用)
Alt + insert 快速生成含有任意形参的构造器,和私有属性的 Getter / Setter 方法等(最常使用)
Alt+Q 显示当前方法的声明
Alt + 7 快速显示类结构,可以显示类中包含的所有属性和方法
Alt + left / right 快速切换代码视图
Alt + Up / Down 在方法间快速移动定位(即光标以方法为单位移动)
"Ctrl + "系列
Ctrl + W 选中文本,连续按可以扩大选中范围(以单词为单位)
Ctrl + Y 删除当前行
Ctrl + D 复制当前行,直接在下一行复制出当前行 (Duplicate复制)
Ctrl + / 添加注释和取消注释,【第一次是添加注释,第二次是取消注释】
Ctrl + F 在当前文件中查找文本 (Find 查找)
Ctrl + R 查找并替换文本(基本可以完成Ctrl + F的功能),支持多行查找,或者只在代码中查找,或者只在注释中查找,或者使用正则表达式查找(Replace 替换)
Ctrl + O 快速重写基类或者接口中的方法 (Override 重写)
Ctrl + H 显示类结构图(类的继承层次) (Hierarhcy层级)
Ctrl + G 快速定位到指定行指定列
Ctrl + [ 快速定位到代码块开始位置
Ctrl + ] 快速定位到代码块结束位置
Ctrl + N 快速搜索和打开类
Ctrl + B 快速定位源码,将光标放在方法上输入 , 可以去到该方法的源码
Ctrl + U 快速转到当前类的父类
组合键系列
Ctrl + Alt + T 将选中的代码使用 if、while、try/catch 等代码块包装起来(功能强大)
Ctrl + Alt + L 快速格式化代码
Ctrl + Alt + I 自动缩进行
Ctrl+Alt+O 优化导入的类和包
4.4 类的成员之一:属性(field)
语法格式:修饰符 数据类型 属性名 = 初始化值 ;
- 说明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.5 类的成员之二:方法(method)
- 方法是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中也称为函数或过程。
- 将功能封装为方法的目的是,可以实现代码重用,简化代码
- Java里的方法不能独立存在,所有的方法必须定义在类里。
方法的声明格式:
修饰符 返回值类型 方法名(参数类型 形参1, 参数类型 形参2, ….){
方法体程序代码
return 返回值;
}
其中:
修饰符:public,缺省,private, protected等
返回值类型:
>没有返回值:void。
>有返回值,声明出返回值的类型。与方法体中“return 返回值”搭配使用
方法名:属于标识符,命名时遵循标识符命名规则和规范,“见名知意”
形参列表:可以包含零个,一个或多个参数。多个参数时,中间用“,”隔开
返回值:方法在执行完毕后返还给调用它的程序的数据。
举例:
public class Person{
private int age;
public int getAge() { //声明方法getAge()
return age;
}
public void setAge(int i) { //声明方法setAge
age = i; //将参数i的值赋给类的成员变量age
}
}
方法的分类:按照是否有形参及返回值
注 意:
(1)必须先声明后使用,且方法必须定义在类的内部
(2)调用一次就执行一次,不调用不执行。
(3)方法中可以调用类中的方法或属性,不可以在方法内部定义方法。
正确示例:
类{
方法1(){
}
方法2(){
}
}
错误示例:
类{
方法1(){
方法2(){ //位置错误
}
}
}
4.5.1 方法的重载
重载的概念:
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
重载的特点:
与返回值类型无关,只看参数列表,且参数列表必须不同。(参数个数或参数类型)。调用时,根据方法参数列表的不同来区别。
重载方法调用:JVM通过方法的参数列表,调用匹配的方法。
先找个数、类型最匹配的
再找个数和类型可以兼容的,如果同时多个方法可以兼容将会报错
重载示例:
//返回两个整数的和
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;}
举例:
public class PrintStream {
public static void print(int i) {……}
public static void print(float f) {……}
public static void print(String s) {……}
public static void main(String[] args) {
print(3);
print(1.2f);
print("hello!");
}
}
4.5.2 方法参数的值传递机制
方法,必须由其所在类或对象调用才有意义。若方法含有参数:
- 形参:方法声明时的参数
- 实参:方法调用时实际传给形参的参数值
Java的实参值如何传入方法呢?
Java里方法的参数传递方式只有一种:值传递。 即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响。
形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参
形参是引用数据类型:将实参引用数据类型变量的“地址值"传递给形参
练习:
1.定义一个int型的数组:int[] arr = new int[]{12,3,3,34,56,77,432};
让数组的每个位置上的值去除以首位置的元素,得到的结果,作为该位置上的新值。遍历新的数组
//正确写法1
for(int i = arr.length – 1;i >= 0;i--){
arr[i] = arr[i] / arr[0];
}
//正确写法2
int temp = arr[0];
for(int i= 0;i < arr.length;i++){
arr[i] = arr[i] / temp;
}
2.
int[] arr = new int[10];
System.out.println(arr);//地址值? [I@d716361
char[] arr1 = new char[10];
System.out.println(arr1); //地址值? 10个空值
3.
(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,以及对应的圆面积。
(3)在main方法中调用printAreas()方法,调用完毕后输出当前半径值。
//Circle类
package demo05;
public class Circle {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double findArea(){
return radius*radius*Math.PI;
}
}
//PassObject类
package demo05;
public class PassObject {
public void printAreas(Circle c,int time){
System.out.println("Radius\t\tArea");
for (int i = 1;i <= time;i++) {
c.setRadius(i);
System.out.println(c.getRadius() + "\t\t" + c.findArea());
}
}
}
//Main类
package demo05;
public class Main {
public static void main(String[] args) {
PassObject passObject = new PassObject();
Circle circle = new Circle(0);
passObject.printAreas(circle, 5);
System.out.println("nuw radius is: " + circle.getRadius());
}
}
>运行结果
Radius Area
1.0 3.141592653589793
2.0 12.566370614359172
3.0 28.274333882308138
4.0 50.26548245743669
5.0 78.53981633974483
nuw radius is: 5.0
4.5.3 递归(recursion)方法
**递归方法调用:**方法自己调用自己的现象就称为递归。
递归的分类: 直接递归、间接递归。
-
直接递归:方法自身调用自己。
public void methodA(){ methodA(); }
-
间接递归:可以理解为A()方法调用B()方法,B()方法调用C()方法,C()方法调用A()方法。
```java
```java
public static void A(){
B();
}
public static void B(){
C();
}
public static void C(){
A();
}
说明:
- 递归方法包含了一种
隐式的循环
。 - 递归方法会
重复执行
某段代码,但这种重复执行无须循环控制。 - 递归一定要向
已知方向
递归,否则这种递归就变成了无穷递归,停不下来,类似于死循环
。最终发生栈内存溢出
。
举例1:计算1 ~ n的和
举例2:
计算斐波那契数列(Fibonacci)的第n个值,斐波那契数列满足如下规律,
1,1,2,3,5,8,13,21,34,55,....
即从第三个数开始,一个数等于前两个数之和。假设f(n)代表斐波那契数列的第n个值,那么f(n)满足:
f(n) = f(n-2) + f(n-1);
//使用递归的写法
int f(int n) {//计算斐波那契数列第n个值是多少
if (n < 1) {//负数是返回特殊值1,表示不计算负数情况
return 1;
}
if (n == 1 || n == 2) {
return 1;
}
return f(n - 2) + f(n - 1);
}
//不用递归
int fValue(int n) {//计算斐波那契数列第n个值是多少
if (n < 1) {//负数是返回特殊值1,表示不计算负数情况
return 1;
}
if (n == 1 || n == 2) {
return 1;
}
//从第三个数开始, 等于 前两个整数相加
int beforeBefore = 1; //相当于n=1时的值
int before = 1;//相当于n=2时的值
int current = beforeBefore + before; //相当于n=3的值
//再完后
for (int i = 4; i <= n; i++) {
beforeBefore = before;
before = current;
current = beforeBefore + before;
/*
假设i=4
beforeBefore = before; //相当于n=2时的值
before = current; //相当于n=3的值
current = beforeBefore + before; //相当于n = 4的值
假设i=5
beforeBefore = before; //相当于n=3的值
before = current; //相当于n = 4的值
current = beforeBefore + before; //相当于n = 5的值
....
*/
}
return current;
}
4.6 对象数组
数组的元素可以是基本数据类型,也可以是引用数据类型。当元素是引用类型中的类时,我们称为对象数组。
例题:
1.定义类Student,包含三个属性:学号number(int),年级state(int),成绩score(int)。
创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
问题一:打印出3年级(state值为3)的学生信息。
问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
提示:
1) 生成随机数:Math.random(),返回值类型double;
2) 四舍五入取整:Math.round(double d),返回值类型long。
//Student类
public class Student {
int number;//学号
int state;//年级
int score;//成绩
public void info(){
System.out.println("number : " + number
+ ",state : " + state + ",score : " + score);
}
}
//StudentTest类
public class StudentTest {
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 + 1);
students[i].state = (int) (Math.random() * 6 + 1);// [1,6]
students[i].score = (int) (Math.random() * 101);// [0,100]
}
// 问题一:打印出3年级(state值为3)的学生信息。
System.out.println("问题一:打印出3年级(state值为3)的学生信息。");
for (int i = 0; i < students.length; i++) {
if (students[i].state == 3) {
// System.out.println(
// "number:" + students[i].number + ",state:" + students[i].state + ",score:" + students[i].score);
students[i].info();
}
}
System.out.println("******************************");
// 问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
// 排序前
System.out.println("问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息");
System.out.println("排序前");
for (int i = 0; i < students.length; i++) {
// System.out.println(
// "number:" + students[i].number + ",state:" +
// students[i].state + ",score:" + students[i].score);
students[i].info();
}
System.out.println();
// 排序:
for (int i = 0; i < students.length - 1; i++) {
for (int j = 0; j < students.length - 1 - i; j++) {
if (students[j].score > students[j + 1].score) {
Student temp = students[j];
students[j] = students[j + 1];
students[j + 1] = temp;
}
}
}
// 排序后:
System.out.println("排序后");
for (int i = 0; i < students.length; i++) {
// System.out.println(
// "number:" + students[i].number + ",state:" +
// students[i].state + ",score:" + students[i].score);
students[i].info();
}
}
}
>运行结果:
问题一:打印出3年级(state值为3)的学生信息。
number : 1,state : 3,score : 98
number : 2,state : 3,score : 60
number : 5,state : 3,score : 71
number : 7,state : 3,score : 72
number : 8,state : 3,score : 72
number : 9,state : 3,score : 24
number : 14,state : 3,score : 0
number : 16,state : 3,score : 68
number : 18,state : 3,score : 29
number : 20,state : 3,score : 61
******************************
问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
排序前
number : 1,state : 3,score : 98
number : 2,state : 3,score : 60
number : 3,state : 1,score : 22
number : 4,state : 6,score : 78
number : 5,state : 3,score : 71
number : 6,state : 5,score : 72
number : 7,state : 3,score : 72
number : 8,state : 3,score : 72
number : 9,state : 3,score : 24
number : 10,state : 1,score : 73
number : 11,state : 2,score : 0
number : 12,state : 2,score : 99
number : 13,state : 6,score : 65
number : 14,state : 3,score : 0
number : 15,state : 5,score : 61
number : 16,state : 3,score : 68
number : 17,state : 2,score : 41
number : 18,state : 3,score : 29
number : 19,state : 2,score : 14
number : 20,state : 3,score : 61
排序后
number : 11,state : 2,score : 0
number : 14,state : 3,score : 0
number : 19,state : 2,score : 14
number : 3,state : 1,score : 22
number : 9,state : 3,score : 24
number : 18,state : 3,score : 29
number : 17,state : 2,score : 41
number : 2,state : 3,score : 60
number : 15,state : 5,score : 61
number : 20,state : 3,score : 61
number : 13,state : 6,score : 65
number : 16,state : 3,score : 68
number : 5,state : 3,score : 71
number : 6,state : 5,score : 72
number : 7,state : 3,score : 72
number : 8,state : 3,score : 72
number : 10,state : 1,score : 73
number : 4,state : 6,score : 78
number : 1,state : 3,score : 98
number : 12,state : 2,score : 99
4.7 关键字:package、import
4.7.1 package(包)
package,称为包,用于指明该文件中定义的类、接口等结构所在的包。
package 顶层包名.子包名 ;
举例:pack1\pack2\PackageTest.java
package pack1.pack2; //指定类PackageTest属于包pack1.pack2
public class PackageTest{
public void display(){
System.out.println("in method display()");
}
}
说明:
- 一个源文件只能有一个声明包的package语句
- package语句作为Java源文件的第一条语句出现。若缺省该语句,则指定为无名包。
- 包名,属于标识符,满足标识符命名的规则和规范(全部小写)、见名知意
- 包通常使用所在公司域名的倒置,取包名时不要使用"
java.xx
"包
- 包通常使用所在公司域名的倒置,取包名时不要使用"
- 包对应于文件系统的目录,package语句中用 “.” 来指明包(目录)的层次,每.一次就表示一层文件目录。
- 同一个包下可以声明多个结构(类、接口),但是不能定义同名的结构(类、接口)。不同的包下可以定义同名的结构(类、接口)
包的作用
- 包可以包含类和子包,划分
项目层次
,便于管理 - 帮助
管理大型软件
系统:将功能相近的类划分到同一个包中。比如:MVC的设计模式 - 解决
类命名冲突
的问题 - 控制
访问权限
MVC设计模式
MVC是一种软件构件模式,目的是为了降低程序开发中代码业务的耦合度。
MVC设计模式将整个程序分为三个层次:视图模型(Viewer)层
,控制器(Controller)层
,与数据模型(Model)层
。这种将程序输入输出、数据处理,以及数据的展示分离开来的设计模式使程序结构变的灵活而且清晰,同时也描述了程序各个对象间的通信方式,降低了程序的耦合性。
视图层viewer:显示数据,为用户提供使用界面,与用户直接进行交互。
>相关工具类 view.utils
>自定义view view.ui
控制层controller:解析用户请求,处理业务逻辑,给予用户响应
>应用界面相关 controller.activity
>存放fragment controller.fragment
>显示列表的适配器 controller.adapter
>服务相关的 controller.service
>抽取的基类 controller.base
模型层model:主要承载数据、处理数据
>数据对象封装 model.bean/domain
>数据库操作类 model.dao
>数据库 model.db
JDK中主要的包介绍
java.lang
----包含一些Java语言的核心类,如String、Math、Integer、 System和Thread,提供常用功能
java.net
----包含执行与网络相关的操作的类和接口。
java.io
----包含能提供多种输入/输出功能的类。
java.util
----包含一些实用工具类,如定义系统特性、接口的集合框架类、使用与日期日历相关的函数。
java.text
----包含了一些java格式化相关的类
java.sql
----包含了java进行JDBC数据库编程的相关类/接口
java.awt
----包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)。
4.7.2 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();
}
}
注意事项
-
import语句,声明在包的声明和类的声明之间。
-
如果需要导入多个类或接口,那么就并列显式多个import语句即可
-
如果使用
a.*
导入结构,表示可以导入a包下的所有的结构。举例:可以使用java.util.*的方式,一次性导入util包下所有的类或接口。 -
如果导入的类或接口是java.lang包下的,或者是当前包下的,则可以省略此import语句。
-
如果已经导入java.a包下的类,那么如果需要使用a包的子包下的类的话,仍然需要导入。
-
如果在代码中使用不同包下的同名的类,那么就需要使用类的全类名的方式指明调用的是哪个类。
-
(了解)
import static
组合的使用:调用指定类或接口下的静态的属性或方法
4.8 特征一:封装性(encapsulation)
所谓封装,就是把客观事物封装成抽象概念的类,并且类可以把自己的数据和方法只向可信的类或者对象开放,向没必要开放的类或者对象隐藏信息。
通俗的讲,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。
Java实现数据封装
- 实现封装就是控制类或成员的可见性范围。这就需要依赖访问控制修饰符,也称为权限修饰符来控制。
- 权限修饰符:
public
、protected
、缺省
、private
。具体访问范围如下:
修饰符 | 本类内部 | 本包内 | 其他包的子类 | 其他包非子类 |
---|---|---|---|---|
private | √ | × | × | × |
缺省 | √ | √ | × | × |
protected | √ | √ | √ | × |
public | √ | √ | √ | √ |
- 具体修饰的结构:
- 外部类:public、缺省
- 成员变量、成员方法、构造器、成员内部类:public、protected、缺省、private
4.8.1 封装性的体现
成员变量/属性私有化
概述: 私有化类的成员变量,提供公共的get和set方法,对外暴露获取和修改属性的功能。
实现步骤:
① 使用 private
修饰成员变量
private 数据类型 变量名 ;
代码如下:
public class Person {
private String name;
private int age;
private boolean marry;
}
② 提供 getXxx
方法 / setXxx
方法,可以访问成员变量,代码如下:
public class Person {
private String name;
private int age;
private boolean marry;
public void setName(String n) {
name = n;
}
public String getName() {
return name;
}
public void setAge(int a) {
age = a;
}
public int getAge() {
return age;
}
public void setMarry(boolean m){
marry = m;
}
public boolean isMarry(){
return marry;
}
}
③ 测试:
public class PersonTest {
public static void main(String[] args) {
Person p = new Person();
//实例变量私有化,跨类是无法直接使用的
/* p.name = "张三";
p.age = 23;
p.marry = true;*/
p.setName("张三");
System.out.println("p.name = " + p.getName());
p.setAge(23);
System.out.println("p.age = " + p.getAge());
p.setMarry(true);
System.out.println("p.marry = " + p.isMarry());
}
}
成员变量封装的好处:
- 让使用者只能通过事先预定的方法来
访问数据
,从而可以在该方法里面加入控制逻辑,限制对成员变量的不合理访问。还可以进行数据检查,从而有利于保证对象信息的完整性。 便于修改
,提高代码的可维护性。主要说的是隐藏的部分,在内部修改了,如果其对外可以的访问方式不变的话,外部根本感觉不到它的修改。例如:Java8->Java9,String从char[]转为byte[]内部实现,而对外的方法不变,我们使用者根本感觉不到它内部的修改。
4.8.2 私有化方法
public class ArrayUtil {
/**
*
* @Description 求int型数组的最大值
* @param arr
* @return
*/
public int max(int[] arr) {
int maxValue = arr[0];
for(int i = 1;i < arr.length;i++){
if(maxValue < arr[i]){
maxValue = arr[i];
}
}
return maxValue;
}
/**
*
* @Description 求int型数组的最小值
* @param arr
* @return
*/
public int min(int[] arr){
int minValue = arr[0];
for(int i = 1;i < arr.length;i++){
if(minValue > arr[i]){
minValue = arr[i];
}
}
return minValue;
}
/**
*
* @Description 求int型数组的总和
* @param arr
* @return
*/
public int sum(int[] arr) {
int sum = 0;
for(int i = 0;i < arr.length;i++){
sum += arr[i];
}
return sum;
}
/**
*
* @Description 求int型数组的元素的平均值
* @param arr
* @return
*/
public int avg(int[] arr) {
int sumValue = sum(arr);
return sumValue / arr.length;
}
// 创建一系列重载的上述方法
// public double max(double[] arr){}
// public float max(float[] arr){}
// public byte max(byte[] arr){}
/**
*
* @Description 遍历数组
* @param arr
*/
public void print(int[] arr) {
for(int i = 0;i < arr.length;i++){
System.out.print(arr[i] + " ");
}
System.out.println();
}
/**
*
* @Description 复制数组arr
* @param arr
* @return
*/
public int[] copy(int[] arr) {
int[] arr1 = new int[arr.length];
for(int i = 0;i < arr.length;i++){
arr1[i] = arr[i];
}
return arr1;
}
/**
*
* @Description 反转数组
* @param arr
*/
public void reverse(int[] arr) {
for(int i = 0,j = arr.length - 1;i < j;i++,j--){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
/**
*
* @Description 数组的排序
* @param arr
* @param desc 指明排序的方式。 ascend:升序 descend:降序
*/
public void sort(int[] arr,String desc) {
if("ascend".equals(desc)){//if(desc.equals("ascend")){
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
// int temp = arr[j];
// arr[j] = arr[j + 1];
// arr[j + 1] = temp;
swap(arr,j,j+1);
}
}
}
}else if ("descend".equals(desc)){
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] < arr[j + 1]) {
// int temp = arr[j];
// arr[j] = arr[j + 1];
// arr[j + 1] = temp;
swap(arr,j,j+1);
}
}
}
}else{
System.out.println("您输入的排序方式有误!");
}
}
private void swap(int[] arr,int i,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
/**
*
* @Description 查找指定的value值在arr数组中出现的位置
* @param arr
* @param value
* @return 返回value值出现的位置 或 -1:未找到
*/
public int getValue(int[] arr, int value) {
//方法:线性查找
for(int i = 0;i < arr.length;i++){
if(value == arr[i]){
return i;
}
}
return - 1;
}
}
注意:
开发中,一般成员实例变量都习惯使用private修饰,再提供相应的public权限的get/set方法访问。
对于final的实例变量,不提供set()方法。(后面final关键字的时候讲)
对于static final的成员变量,习惯上使用public修饰。
4.9 类的成员之三:构造器(Constructor)
构造器的作用
new对象,并在new对象的时候为实例变量赋值。
举例:Person p = new Person(“Peter”,15)
;
解释:如同我们规定每个“人”一出生就必须先洗澡,我们就可以在“人”的构造器中加入完成“洗澡”的程序代码,于是每个“人”一出生就会自动完成“洗澡”,程序就不必再在每个人刚出生时一个一个地告诉他们要“洗澡”了。
构造器的语法格式
[修饰符] class 类名{
[修饰符] 构造器名(){
// 实例初始化代码
}
[修饰符] 构造器名(参数列表){
// 实例初始化代码
}
}
说明:
- 构造器名必须与它所在的类名必须相同。
- 它没有返回值,所以不需要返回值类型,也不需要void。
- 构造器的修饰符只能是权限修饰符,不能被其他任何修饰。比如,不能被static、final、synchronized、abstract、native修饰,不能有return语句返回值。
代码如下:
public class Student {
private String name;
private int age;
// 无参构造
public Student() {}
// 有参构造
public Student(String n,int a) {
name = n;
age = a;
}
public String getName() {
return name;
}
public void setName(String n) {
name = n;
}
public int getAge() {
return age;
}
public void setAge(int a) {
age = a;
}
public String getInfo(){
return "姓名:" + name +",年龄:" + age;
}
}
public class TestStudent {
public static void main(String[] args) {
//调用无参构造创建学生对象
Student s1 = new Student();
//调用有参构造创建学生对象
Student s2 = new Student("张三",23);
System.out.println(s1.getInfo());
System.out.println(s2.getInfo());
}
}
使用说明
-
当我们没有显式的声明类中的构造器时,系统会默认提供一个无参的构造器并且该构造器的修饰符默认与类的修饰符相同
-
当我们显式的定义类的构造器以后,系统就不再提供默认的无参的构造器了。
-
在类中,至少会存在一个构造器。
-
构造器是可以重载的。
练习:
(1)定义Student类,有4个属性:
String name;
int age;
String school;
String major;
(2)定义Student类的3个构造器:
- 第一个构造器Student(String n, int a)设置类的name和age属性;
- 第二个构造器Student(String n, int a, String s)设置类的name, age 和school属性;
- 第三个构造器Student(String n, int a, String s, String m)设置类的name, age ,school和major属性;
(3)在main方法中分别调用不同的构造器创建的对象,并输出其属性值。
public class Student {
String name;
int age;
String school;
String major;
public Student(String n, int a) {
name = n;
age = a;
}
public Student(String n, int a, String s) {
name = n;
age = a;
school = s;
}
public Student(String n, int a, String s, String m) {
name = n;
age = a;
school = s;
major = m;
}
public static void main(String[] args) {
Student s1 = new Student("田大赐", 20);
Student s2 = new Student("田二赐", 21, "北大");
Student s3 = new Student("田三赐", 22, "清华", "Java");
System.out.println(s1.name + " " + s1.age + " " + s1.school + " " + s1.major);
System.out.println(s2.name + " " + s2.age + " " + s2.school + " " + s2.major);
System.out.println(s3.name + " " + s3.age + " " + s3.school + " " + s3.major);
}
}
>运行结果
田大赐 20 null null
田二赐 21 北大 null
田三赐 22 清华 Java