1.方法的重载
①需求
计数器类中已有方法:做两个int类型的加法
public int add(int a, int b)
想要增加新的方法:做两个double类型的加法
public double add(double a, double b)
为了满足更多使用情况,还想有更多方法:
public int add(int a, int b, int c)
小结:在一个类中,很可能会有很多类似的需求,为了满足这些需求,我们会声明很多相似的方法。同时为了让方法的调用者体验更好、更容易找到所需方法,这些功能相近的方法最好使用『同一个方法名』。
②前提
- 同一个类中
- 同名的方法
③方法重载的好处
- 没有重载不方便:让方法调用者,在调用方法的时候,不必为了相似的功能而查阅文档,查找各种不同的方法名,降低学习成本,提高开发效率。
- 有了重置很方便:在调用一系列重载的方法时,感觉上就像是在调用同一个方法。对使用者来说,只需要知道一个方法名就能够应对各种不同情况。
④规则限制
要么是参数个数不同
要么是参数类型不同
⑤重载方法举例
[1]参数个数不同
public int add(int a, int b)
public int add(int a, int b, int c)
[2]参数类型不同
public int add(int a, int b)
public double add(double a, double b)
或:
public double add(int a, double b)
public double add(double a, int b)
⑥重载练习
public class Calculater {
int mOL(int i){
return i*i;
}
int mOL(int i,int j){
return j*i;
}
String mOL(String value){
return value;
}
}
public class CalculaterTest {
public static void main(String[] args) {
Calculater c=new Calculater();
int ci = c.mOL(5);
System.out.println(ci);
ci = c.mOL(5*9);
System.out.println(ci);
String cs = c.mOL("this is string!");
System.out.println(cs);
}
}
2.方法的可变参数
①需求
在实际开发过程中,确实有一些情况不确定在调用方法时传入几个参数。所以为了让调用方法时能够弹性传参,JavaSE5.0标准增加了可变参数功能。
②声明和调用
// 能够计算任意个数整数之和的加法
// 使用String ... args来声明可变参数
public String add(String ... args) {
String sum = "";
// 在方法体内,可变参数按照数组形式来处理
for (int i = 0; i < args.length; i++) {
sum = sum + args[i];
}
return sum;
}
测试代码:
Calculater c=new Calculater();
System.out.println(c.add("a"));
System.out.println(c.add("a","b"));
System.out.println(c.add("a","b","c"));
③语法规则
- 声明格式:方法名(参数的类型名…参数名)
- 可变个数形参的方法与同名的方法之间,彼此构成重载
- 可变参数方法的使用与方法参数部分使用数组是一致的
- 方法有可变形参,需要放在形参声明的最后
- 一个方法只能声明一个可变形参
- 当调用方法时实际传入的参数既匹配可变参数列表方法,又匹配一个具体的参数列表方法,那么系统会优先调用具体的参数列表方法
举例:调用方法add(5, 3)
可变参数方法:add(int … args)
具体参数方法:add(int i, int j)【系统会调用这个方法】
3.方法的值传递机制
①值传递
值传递不会改变变量的值,相当于重新创建了新的变量
②地址值传递
地址值传递会改变变量的值,相当于改变了地址指向变量的值
public class Value {
void values(int i){
System.out.println("改变值之前:"+i);
i+=5;
System.out.println("改变值之后:"+i);
}
void address(int i[]){
System.out.println("改变值之前:"+i[0]);
i[0]+=5;
System.out.println("改变值之后:"+i[0]);
}
}
public class ValueTest {
public static void main(String[] args) {
int vs1=5;
Value v1 = new Value();
System.out.println("值传递调用函数前:"+vs1);
v1.values(vs1);
System.out.println("值传递调用函数后:"+vs1);
System.out.println("===========================================");
int vs2[]=new int[1];
vs2[0]=5;
Value v2 = new Value();
System.out.println("地址值传递调用函数前:"+vs2[0]);
v2.address(vs2);
System.out.println("地址值传递调用函数后:"+vs2[0]);
}
}
5、递归
①概念
方法自己调用自己。使用递归想要达到的目的是让方法中的代码重复执行,而且往往是在上一次执行的结果的基础上,再进一步执行。
②代码示例
[1]计算1~N的和
// 计算1~N之间的总和:使用递归
public int sumOperationRecursion(int number) {
if (number == 1) {
return 1;
}else{
return number + sumOperationRecursion(number - 1);
}
}
[2]没有退出机制的递归调用
// 没有退出机制的递归调用
public void recursionToDie() {
recursionToDie();
}
Exception in thread “main” java.lang.StackOverflowError
at com.atguigu.object.test.MethodRecursion.recursionToDie(MethodRecursion.java:35)
at com.atguigu.object.test.MethodRecursion.recursionToDie(MethodRecursion.java:35)
at com.atguigu.object.test.MethodRecursion.recursionToDie(MethodRecursion.java:35)
at com.atguigu.object.test.MethodRecursion.recursionToDie(MethodRecursion.java:35)
at com.atguigu.object.test.MethodRecursion.recursionToDie(MethodRecursion.java:35)
at com.atguigu.object.test.MethodRecursion.recursionToDie(MethodRecursion.java:35)
内存耗尽的原因:方法每一次开始执行时都会向系统申请栈内存中的一块空间用来存放局部变量。方法结束时释放这块空间。而没有退出机制的递归调用会不断申请新空间,而完全不释放。
栈:stack
堆:heap
[3]用递归实现阶乘
5!=5×4×3×2×1
// 声明一个方法用来实现阶乘
public int factorial(int i) {
if (i == 1) {
return 1;
} else {
return i * factorial(i - 1);
}
}
6、封装
①含义
将对象中数据或代码逻辑隐藏起来。对数据的操作在类的内部完成,对外界隐藏实现的细节。
②好处
- 对象(或组件)内部代码实现的细节可以对外隐藏。
- 简化外部使用对象时的操作难度。外部使用对象时,调用对象暴露出来的方法即可。
- 让整个系统的开发组件化、模块化程度更高,更有利于实现:高内聚、低耦合。
③示例
public class MarryObject {
// 将属性的权限修饰符设置为私有,不允许外部直接访问
private int age;
// 对外暴露的获取数据的getXxx()方法
public int getAge() {
return age;
}
// 对外暴露的设置数据的setXxx()方法
public void setAge(int ageOutter) {
// 在方法内部,根据内部的逻辑,对外界数据进行修正
if (ageOutter < 20) {
age = 20;
} else if (ageOutter > 60) {
age = 60;
} else {
age = ageOutter;
}
}
}
④权限修饰符
修饰符名称 | 含义 | 本类 | 同包其他类 | 子类 | 同工程其他类 |
---|---|---|---|---|---|
private | 私有 | √ | × | × | × |
default | 缺省 | √ | √ | × | × |
protected | 受保护 | √ | √ | √ | × |
public | 公共 | √ | √ | √ | √ |
PS:对class的权限修饰符只有public和缺省两种
- public:表示这个类可以在工程中任意位置访问(开发中实际使用的方式)
- 缺省:表示这个类只能在同一个包内访问(实际开发不会使用这种方式)
7、构造器
①构造器
当我们使用new关键字创建一个类的对象时,就是在使用这个类的构造器了:
如果我们没有明确声明构造器,那么系统会给类分配一个隐式的构造器。
②构造器的作用
- 作用1:创建对象。
- 作用2:在创建对象的过程中,对类进行初始化操作。这些操作写在构造器的大括号中。
- 初始化操作放到构造器里面,由构造器自动完成,程序员就不必在创建对象后还想着对这对象做初始化操作。
③构造器的组成部分
④构造器的参数
[1]有一个参数构造器例子
public class Soldier {
private String soldierName;
public Soldier(String soldierName) {
this.soldierName = soldierName;
}
}
注意:当类中声明了有参构造器之后,系统将不再给这个类分配无参的构造器。
[2]一个类可以有多个构造器
根据参数列表不同,多个构造器之间是重载关系。规则和方法重载一致:
- 要么参数个数不同
- 要么参数类型不同
public class Soldier {
private int age;
private String soldierName;
private String weapon;
private String gender;
public Soldier() {
}
public Soldier(int age) {
this.age = age;
}
public Soldier(String soldierName) {
this.soldierName = soldierName;
}
public Soldier(String soldierName, String weapon) {
this.soldierName = soldierName;
this.weapon = weapon;
}
public Soldier(String soldierName, String weapon, String gender) {
this.soldierName = soldierName;
this.weapon = weapon;
this.gender = gender;
}
public Soldier(int age, String soldierName, String weapon, String gender) {
this.gender = gender;
this.weapon = weapon;
this.soldierName = soldierName;
this.age = age;
}
}
⑤构造器相关语法规则
- Java语言中,每个类都至少有一个构造器
- 默认构造器的修饰符与所属类的修饰符一致
- 一旦显式定义了构造器,则系统不再提供默认构造器
- 一个类可以创建多个重载的构造器
- 父类的构造器不可被子类继承
⑥IDEA相关快捷键
[1]唤出快捷菜单
Alt+Insert
[2]声明无参构造器
当快捷菜单中选中的是Constructor时,回车,弹出下面窗口:
[3]声明全部参数构造器
[4]在快捷菜单输入字符匹配菜单项
输入gets就可以直接匹配到菜单项:Getter and Setter
[5]生成getter和setter方法
通常针对所有属性生成getter、setter方法
[6]生成toString()方法
⑦类的属性赋值的顺序
- 系统根据这个属性的类型来设置默认值。
private int age;
- 显示初始化
private int age = 6;
- 构造器初始化
public Person(int age) {
this.age = age;
}
- 调用方法或直接给属性赋值
person.setAge(5);
或
person.age = 18;
⑧.构造器练习
编写两个类,TriAngle,TriAngleTest,其中TriAngle类中声明私有的底边长base和高height,同时声明公共方法访问私有变量。此外,提供类必要的构造器。另一个类中使用这些公共方法,计算三角形的面积。
public class TriAngle {
private double base;
private double height;
public TriAngle() {
base=height=0;
}
public TriAngle(double base, double height) {
this.base = base;
this.height = height;
}
public void s(){
System.out.println("该三角型面积为:"+base*height/2);
}
}
public class TriAngleTest {
public static void main(String[] args) {
TriAngle t1 = new TriAngle(10,20);
TriAngle t2 = new TriAngle();
t1.s();
t2.s();
}
}
8、JavaBean
①实际项目开发中用到的类
- JavaBean
- 用来描述现实世界中的具体数据:Book、Employee、Department、Product、……
- 也有其他名称:domain(领域模型)、POJO(Plain old Java Object普通的传统的Java对象)、entity(实体类)
- 功能性组件:用来执行具体代码逻辑对应的操作
- BookServlet
- BookService
- BookDao
- 工具类:通常用来把某个特定操作封装到工具方法中。工具类通常是用类名来直接调用方法。
- Aarrys.sort()
②JavaBean的要求
必须有的组成部分:
- 私有的属性
- 针对私有属性设置的公共的getter()、setter()方法
- 无参构造器
③getter()和setter()方法的规则
属性声明:
private int age;
getter()、setter()方法:
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
规则描述如下:
- getXxx()或setXxx()方法取方法名字符串
- 去掉get或set(剩下Xxx)
- Xxx首字母小写
④IDEA生成UML图
9、this关键字
①含义
类的方法中:代表调用当前方法的对象
②this能干什么
[1]调用属性
System.out.println("我的年龄:" + this.age);
System.out.println("我的姓名:" + this.soldierName);
System.out.println("我的武器:" + this.weapon);
[2]调用方法
System.out.println("我的性别:" + this.getGender());
[3]调用构造器
在类中的某个构造器中调用这个类的其他构造器:
public class This {
int x,y;
String name;
public This(int x) {
System.out.println("无参构造器");
this.x = x;
}
public This(String name) {
this(569);
System.out.println("字符串构造器");
this.name = name;
}
public This(int x, int y) {
this("aaaaa");
System.out.println("两参构造器");
this.x = x;
this.y = y;
}
}
public class ThisTest {
public static void main(String[] args) {
This t= new This(5,9);
}
}
[4]this调用构造器的规则
-
在构造器中调用其他构造器,this()语句必须在第一行
-
各个构造器之间调用不能形成闭环,如a->b,b->c,c->a
-
一个构造器中调用其他构造器的操作只能有一个
10、package关键字
用来声明当前类所在的包。package声明所在包的语句必须是在类的第一行。若缺省该语句,则指定为无名包。
11、import关键字
在JDK编译Java源程序的时候,并不能保证所有的类都能够被JDK默认识别到。JDK无法默认识别的类就需要我们通过import语句导入。
- 精确导入:在import关键字后面指定全类名
import java.util.Scanner;
- 全部导入:在import关键字后面指定包名.*
import java.util.*;
语法规则:
- 使用的位置:在package声明和类声明之间
- 如果导入的类或接口是java.lang包下的,或者是当前包下的,则可以省略此import语句。
- 如果导入一个类之后,又需要用到另一个同名的类,那么就需要使用全类名来引用
// 这里导入了一个Book类
import java.awt.print.Book;
public class ImportTest {
public static void main(String[] args) {
// 但是这里又要使用另外一个Book类
// 为了区分二者,这里使用全类名来引用
com.atguigu.object.test.Book book = new com.atguigu.object.test.Book();
}
}
- 如果已经导入java.a包下的类。那么如果需要使用a包的子包下的类的话,仍然需要导入。
- import static组合的使用:静态导入。让当前类可以直接调用导入的类中的静态属性或方法,不必写类名了。