一、构造方法
1、构造方法的概念
-
语法格式:
class 类名{ 类名(形参列表){ 构造方法体; } } 例如: class Person{ Person(){ -Person类中的构造方法 } }
-
构造方法名与类名相同并且没有返回值类型,连void都不许有
2、默认构造方法
-
当一个类中没有定义的构造方法时,编译器会自动添加一个无参空构造方法,叫做默认/缺省构造放阿飞,如:Person(){}
-
若类中出现构造方法,则编译器不再提供任何形式的构造方法。
3、构造方法的作用
- 使用new关键字创建对象时会自动调用构造方法实现成员变量初始化工作。
/*
编程实现Point类的定义并向Point类添加构造方法
Point()默认创建原点对象
Point(int i, int j)根据参数创建点对象
*/
public class Point {
int x;//用于描述横坐标的成员变量
int y;//用于描述纵坐标的成员变量
//自定义构造方法默认创建远点对象
Point() {}
//自定义构造方法根据参数创建点对象
Point(int i, int j) {
x = i;
y = j;
}
//自定义成员方法打印所有的特征
void show() {
System.out.println("X = " + x + ", Y = " + y);
}
public static void main(String [] args) {
//声明一个Point类型的引用指向Point类型的对象
//使用无参构造方法
Point p1 = new Point();
p1.show();
//使用有参构造方法
Point p2 = new Point(2, 3);
p2.show();
Point p3 = new Point(-3, 3);
p3.show();
}
}
二、方法重载
1、方法重载的概念
- 若方法名称相同,参数列表不同,这样的方法之间构成重载关系(Overload)
2、重载的体现形式
- 方法重载的主要形式体现在:参数的个数不同、参数的类型不同、参数的顺序不同,与返回值类型和形参变量名无关,但建议返回值类型最好相同。
- 判断方法能够构成重载的核心:调用方法时能都加以区分。
/*
编程实现方法重载主要形式的测试
*/
public class OverloadTest {
//自定义成员方法
void show() {
System.out.println("show");
}
void show(int i) {//体现在方法参数个数不同
System.out.println("show(int)");
}
void show(int i, double d) {//体现在方法参数个数不同
System.out.println("show(int, double)");
}
void show(int i, int d) {//体现在方法参数的类型不同
System.out.println("show(int, int)");
}
void show(double d, int i) {//体现在方法参数顺序不同
System.out.println("show(double, int)");
}
/*void show(double b, int c) {//error 与参数的变量名无关
System.out.println("show(double, int)");
}
int show(double b, int c) {//error 与返回值类型无关
System.out.println("show(double, int)");
}*/
public static void main(String [] args) {
//声明一个OverloadTest类型的引用指向该类型的对象
OverloadTest ot = new OverloadTest();
//调用show方法
ot.show();
ot.show(66);
ot.show(66, 3.14);
ot.show(66,44);
ot.show(3.14, 66);
}
}
练习题目
• 编程实现为Point类添加重载的成员方法: up() – 实现纵坐标减1的功能。 up(int dy) – 实现纵坐标减去参数指定数值的功能。
• 测试重载方法的调用规则
/*
编程实现Point类的定义并向Point类添加构造方法
Point()默认创建原点对象
Point(int i, int j)根据参数创建点对象
*/
public class Point {
int x;//用于描述横坐标的成员变量
int y;//用于描述纵坐标的成员变量
//自定义构造方法默认创建远点对象
Point() {}
//自定义构造方法根据参数创建点对象
Point(int i, int j) {
x = i;
y = j;
}
//自定义成员方法打印所有的特征
void show() {
System.out.println("X = " + x + ", Y = " + y);
}
//自定义成员方法实现纵坐标减一的行为
void up() {
y--;
}
//自定义成员方法实现纵坐标减去指定参数的行为
void up(int i) {
y -= i;
}
public static void main(String [] args) {
//声明一个Point类型的引用指向Point类型的对象
//使用无参构造方法
Point p1 = new Point();
p1.show();
//使用有参构造方法
Point p2 = new Point(2, 3);
p2.show();
Point p3 = new Point(-3, 3);
p3.show();
System.out.println("----------------");
//使用方法重载
p2.up();
p2.show();
p3.up(2);
p3.show();
}
}
3、重载的实际意义
-
方法重载的实际意义在于调用者只需要记住一个方法名就可以调用各种不同的版本,来实现各种不同的功能。
-
如:java.io.PrintStream类中的Println方法。
三、this关键字
1、基本概念
- 若在构造方法中出现了this关键字,则代表当前正在构造的对象
- 若在成员方法中出现了this关键字,则代表当前正在调用的对象
- this关键字本质上就是当前类类型的引用变量
/*
编程实现this关键字的使用
*/
public class ThisTest {
//自定义构造方法
ThisTest() {
//this代表正在构造的对象
System.out.println("在构造方法中,this = " + this);
}
//自定义成员方法
void show() {
//this代表正在调用的对象
System.out.println("在成员方法中,this = " + this);
}
public static void main(String[] args) {
//声明ThisTest类型的应用指向该类型的对象
ThisTest tt = new ThisTest();
//调用show方法
tt.show();
System.out.println("在main方法中,tt = " + tt);
}
}
2、工作原理
- 在构造方法中和成员方法中访问成员变量时,编译器会加上this.的前缀,而this.相当于汉语中“我的”,当不同的对象调用同一个方法时,由于调用方法的对象不同导致this关键字不同,从而this.方式访问的结果也就随之不同。
3、使用方式
-
当局部变量名与成员变量名相同时,在方法体中会优先使用局部变量(就近原则),若希望使用成员变量,则需要在成员变量的前面加上this.的前缀,明确要求该变量是成员变量(重中之重)。
String name;//用于描述姓名的成员变量 int age; //用于描述年龄的成员变量 //自定义构造方法:有参构造方法 Person(String name, int age) { //System.out.println("我就是自定义构造方法!"); //name = "张飞"; //age = 30; this.name = name;//this.name指Person方法外的成员变量name this.age = age;//this.age指Person方法外的成员变量age }
-
this关键字除了可以通过this.的方式调用成员变量和成员方法外,还可以作为方法的返回值(重点)。
//自定义成员方法实现所有特征的打印 //隐含这this关键字 this关键字代表当前正在调用的对象 void show() { //每当打印成员变量的数值时,让年龄增长一岁 this.grow();//调用grow方法 当不存在歧义冲突时,this可以省略 //当不存在歧义冲突时,this可以省略 System.out.println("我是" + this.name + ", 今年" + this.age + "岁。"); } //自定义成员方法实现年龄增长一岁 void grow() { age++; }
//自定义成员方法实现Person类型对象的获取并返回的行为 Person getPerson() { return this; } System.out.println("---------------"); //调用成员方法获取对象 Person p4 = p1.getPerson(); System.out.println("p1 = " + p1); System.out.println("p4 = " + p4);
-
在构造方法的第一行可以使用this()的方式来调用本类中的其他构造方法(了解)。
/* 编程实现Boy类的定义 */ public class Boy { String name; //自定义构造方法 //当两个构造参数的第一行都用this来调用构造参数是会报错:错误: 递归构造器调用 Boy() { //this("赵云");//调用本类中有参构造方法 System.out.println("无参构造方法!"); } Boy(String name) { this();//调用本类中无参构造方法 System.out.println("有参构造参数!"); this.name = name; } //自定义成员方法实现特征打印 void show() { System.out.println("我的名字是:" + name); } public static void main(String [] args) { //声明Boy类型的引用指向该类型的对象 //实现无参构造方法打印特征 Boy b1 = new Boy(); //name = "赵云"; b1.show(); System.out.println("---------------"); //实现有参构造方法打印特征 Boy b2 = new Boy("黄忠"); b2.show(); } }
注意事项:
-
引用类型变量用于存放对象的地址,可以给引用类型赋值为null,表示不指向任何对象。
-
当某个引用类型变量为null时,无法对对象实施访问(因为它没有指向任何对象)。此时,如果通过引用访问成员变量或调用方法,会产生NUllPointException异常。
//引用变量的数值可以为空 //java.lang.NullPointerException: 编译ok,运行会发生NullPointerException空指针异常 //异常还有算术异常,数组下标溢出异常 //声明一个Boy类型的引用指向该类型的空对象 Boy b3 = null; b3.show();
四、方法递归调用
1、递归基本概念
-
递归的本质就是指在方法体内部直接或间接调用当前方法自身的形式。
-
/* 案例题目 编程实现参数n的阶乘并返回,所谓阶乘就是从1累乘到n的结果。 */ //自定义阶乘类 public class Factorial { //自定义成员方法实现阶乘的过程 递推 int doTest(int n) { //n = m; int num = 1; for(int i = 1; i <= n; i++) { num *= i; } return num; } //自定义成员方法实现递归实现阶乘的过程 int show(int n) { if(1 == n) { return 1; } return n*show(n-1); //if n = 5; show(5) = 5*show(4); => //show(4) = 4*show(3); => //show(3) = 3*show(2); => //show(2) = 2*show(1); => //show(1) = 1; => 1 //递归从n开始一层层推导到1,而后根据1一层层反推到n从而得到n } public static void main(String [] args) { //声明Factorial类型的引用指向该类型的对象 Factorial f = new Factorial(); ///f.doTest(5); //f.show(); //System.out.println("--------------------"); int res = f.doTest(5); System.out.println("阶乘的结果是:" + res); System.out.println("--------------------"); //输出递归得到的值 int k = f.show(4); System.out.println("阶乘的结果是:" + k); } }
2、注意事项
- 使用递归必须有递归的规律以及退出的条件
- 使用递归必须使得问题简单化而不是复杂化
- 若递归影响到程序的执行性能,则使用递推取代之。
/*
案例题目
1、编程实现费式数列中第n项的数值并返回。
2、费式数列:1 1 2 3 5 8 13 21 ....
*/
public class FeiShi {
//自定义成员方法用递归的方式实现费式数列中数值返回
int show(int n) {
if(1 == n || 2 == n) return 1;
return show(n-1)+show(n-2);
}
//自定义成员方法用递推的方式实现费式数列中数值的返回
int doGet(int n) {
int num = 0;
/*int[] arr = new int[n];
for(int i = 1; i <= n; i++) {
if(i == 1 || i == 2){
arr[i-1] = 1;
num = arr[i-1];
}else {
arr[i-1] = arr[i-2] + arr[i-3];
num = arr[i-1];
}
}*/
//相比较上面使用数组下面的方式代码更加简单
int ia = 1;
int ib = 1;
for(int i = 3; i <= n; i++) {
int ic = ia + ib;
ia = ib;
ib = ic;
num = ib;
}
return num;
}
public static void main(String [] args) {
//声明一个feishi类型的引用指向该类型的对象
FeiShi fs = new FeiShi();
//实现递归的打印
int res = fs.show(6);//当数值过大时,程序运行耗时长,性能较低,不建议使用递归方式
System.out.println("第n项的数值是:" + res);
System.out.println("----------------");
//实现递推的打印
int res1 = fs.doGet(55);
System.out.println("第n项的数值是:" + res1);
}
}
3、代码的拆分实现
/*
案例题目
1、编程实现费式数列中第n项的数值并返回。
2、费式数列:1 1 2 3 5 8 13 21 ....
*/
//功能类/封装类
public class Fee {
//自定义成员方法用递归的方式实现费式数列中数值返回
int show(int n) {
if(1 == n || 2 == n) return 1;
return show(n-1)+show(n-2);
}
//自定义成员方法用递推的方式实现费式数列中数值的返回
int doGet(int n) {
int num = 0;
/*int[] arr = new int[n];
for(int i = 1; i <= n; i++) {
if(i == 1 || i == 2){
arr[i-1] = 1;
num = arr[i-1];
}else {
arr[i-1] = arr[i-2] + arr[i-3];
num = arr[i-1];
}
}*/
//相比较上面使用数组下面的方式代码更加简单
int ia = 1;
int ib = 1;
for(int i = 3; i <= n; i++) {
int ic = ia + ib;
ia = ib;
ib = ic;
num = ib;
}
return num;
}
/*public static void main(String [] args) {
//声明一个feishi类型的引用指向该类型的对象
Fee ft = new Fee();
//实现递归的打印
int res = ft.show(6);//当数值过大时,程序运行耗时长,性能较低,不建议使用递归方式
System.out.println("第n项的数值是:" + res);
System.out.println("----------------");
//实现递推的打印
int res1 = ft.doGet(55);
System.out.println("第n项的数值是:" + res1);
}*/
}
/*
编程实现对费式数列类的测试
*/
//测试类
public class FeeTest {
public static void main(String [] args) {
//声明一个feishi类型的引用指向该类型的对象
Fee ft = new Fee();
//实现递归的打印
int res = ft.show(6);//当数值过大时,程序运行耗时长,性能较低,不建议使用递归方式
System.out.println("第n项的数值是:" + res);
System.out.println("----------------");
//实现递推的打印
int res1 = ft.doGet(55);
System.out.println("第n项的数值是:" + res1);
}
}
五、封装
1、封装的概念
- 通常情况下可以在测试类给成员变量赋值一些合法但不合理的数值,无论是编译阶段还是运行阶段都不会报错或者给出提示,此时与现实生活不符。
- 为避免上述错误的发生,就需要对成员变量进行密封包装处理,来隐藏成员变量的细节以及保证成员变量数值的合理性,该机制就叫做封装。
2、封装的实现流程
- 私有化成员变量,使用private关键字修饰
- 提供公有的get和set方法,并在方法体中进行合理值的判断
- 在构造方法中调用set方法进行合理值判断
/*
编程实现Student类的实现 封装类
*/
public class Student {
//1、私有化成员变量,使用private关键字修饰
//private关键字修饰表示私有的含义,也就是该成员变量只能在当前类内部使用
private int id; //用于描述学员学号的成员变量
private String name; //用于描述学员姓名的成员变量
//
public Student() {
}
public Student(int id, String name) {
//this.id = id;
//this.name = name;
setId(id);
setName(name);
}
//2、提供公有的get和set方法,并在方法体中对数值进行合理的判断
//使用public关键字修饰表示公有的含义,该方法可以在任意位置使用
public int getId() {
return id;
}
public void setId(int id) {
if(id > 0) {
this.id = id;
}else {
System.out.println("学号不合理!")
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//自定义成员方法实现特征的打印
//什么修饰符都没有叫做默认的访问权限,介于private和public之间。
void show() {
//System.out.println("我是" + name + ",id是:" + id);
System.out.println("我是" + getName() + ",id是:" + getId());
}
}
/*
编程实现Student类的测试 测试类
*/
public class StudentTest {
public static void main(String [] args) {
//声明Student类型的引用指向Student类型的对象
Student s1 = new Student();
//对成员变量进行赋值并打印
//s1.id = 1001;
//s1.name = "赵云";
//System.out.println("学生的id是:" + s1.id + " 姓名是:" + s1.name);
s1.setId(1001);
s1.setName("赵云");
s1.show();
System.out.println("---------------------");
//使用有参方式构造对象并打印特征
Student s2 = new Student();
s2.show();
}
}
4、案例题目:
- 提示用户输入班级学生人数以及每个学生的信息,学生的信息有:学号、姓名,最后分别打印出来。
- 提示:Student[] arr = new Student[num];
/*
编程实现Student类的实现 封装类
*/
public class Student {
//1、私有化成员变量,使用private关键字修饰
//private关键字修饰表示私有的含义,也就是该成员变量只能在当前类内部使用
private int id; //用于描述学员学号的成员变量
private String name; //用于描述学员姓名的成员变量
//
public Student() {
}
public Student(int id, String name) {
//this.id = id;
//this.name = name;
setId(id);
setName(name);
}
//2、提供公有的get和set方法,并在方法体中对数值进行合理的判断
//使用public关键字修饰表示公有的含义,该方法可以在任意位置使用
public int getId() {
return id;
}
public void setId(int id) {
if(id > 0) {
this.id = id;
}else {
System.out.println("学号不合理!");
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//自定义成员方法实现特征的打印
//什么修饰符都没有叫做默认的访问权限,介于private和public之间。
void show() {
//System.out.println("我是" + name + ",id是:" + id);
System.out.println("我是" + getName() + ",id是:" + getId());
}
}
/*
编程实现学生信息的录入和打印 测试类
*/
import java.util.Scanner;
public class StudentTest2 {
public static void main(String [] args) {
Scanner sc = new Scanner(System.in);
Student s3 = new Student();
//提示输入学生的人数
System.out.print("请输入学生的人数:");
int num = sc.nextInt();
//声明一个student类型的数组,用于存放学生信息。
Student[] arr = new Student[num];
for(int i = 0; i < arr.length; i++) {
System.out.println("请输入第" + (i+1) + "个学生的信息(学号 姓名):");
arr[i] = new Student(sc.nextInt(), sc.next());
}
//输出学生的信息
System.out.println("该班级所有学生的信息:");
for(int i = 0; i < arr.length; i++) {
//System.out.println(arr[i]);
arr[i].show();
}
}
}
六、JavaBea的概念
- JavaBean是一种Java语言写成的可重用组件,其他Java类可以通过反射机制发现和操作这些JavaBean的属性
- JavaBean本质就是符合一下标准的Java类:
- 类是公共的
- 有一个无参的公告的构造器
- 有属性,且有对应的get、set方法
文章内容输出来源:拉勾教育Java高薪训练营