1 方法
- 方法:将具有独立功能的代码块组成一个整体,使其具有特殊功能的代码集
- 方法必须先创建才能使用,该过程称为方法定义
- 方法创建后并不是直接运行,需要手动使用后才执行,该过程称为方法调用
1.1 方法的定义和调用
- 定义格式
public static void 方法名() {
//f方法体;
}
- 方法调用格式
方法名();
- 案例1:奇偶数判断
public class Demo {
public static void main(String[] args) {
demo(); //main方法中调用其他方法
}
public static void demo() {
int a = 9;
if(a%2==0) {
System.out.println("偶数");
}else {
System.out.println("奇数"); //奇数
}
}
}
- 案例2:求较大值
public class Demo {
public static void main(String[] args) {
getMax();
}
public static void getMax() {
int a = 10;
int b = 20;
if(a>b) {
System.out.println("a更大");
}else {
System.out.println("b更大"); //b更大
}
}
}
1.2 带参数方法的定义和调用
- 定义格式
public static void 方法名(参数) {...}
- 单个参数格式
public static void 方法名(数据类型 变量名) {...}
public static void getMax(int arr) {...}
- 多个参数格式
public static void 方法名(数据类型 变量名1,数据类型 变量名2,...) {...}
public static void getMax(int arr1,int arr2,...) {...}
- 调用格式
方法名(参数);
- 单个参数调用
方法名(变量名/常量名);
getMax(5);
- 多个参数调用
方法名(变量名1/常量名1,变量名2/常量名2,...);
getMax(5,6);
-
注意
:方法调用时,参数的数量和类型必须和方法定义中的设置相匹配,否则就会报错 -
案例1:判断奇偶数
public class Demo {
public static void main(String[] args) {
//常数值得调用
IsEvenNumber(10); //偶数
//变量的调用
int num = 10;
IsEvenNumber(num); //偶数
}
public static void isEvenNumber(int number) {
if(number%2 == 0) {
System.out.println("偶数");
}else {
System.out.println("奇数");
}
}
}
-
形参和实参
-
形参:方法定义中的参数,例如:
int number
-
实参:方法调用中的参数,例如:
10、num
-
案例1:比较大小
public class Demo {
public static void main(String[] args) {
getMax(10,90); //b更大
}
public static void getMax(int a,int b) {
if(a>b) {
System.out.println("a更大");
}else {
System.out.println("b更大");
}
}
}
1.3 带返回值方法的定义和调用
- 定义格式
public static 数据类型 方法名(参数) {
return 数据:
}
//案例1
public static boolean isEvenNumber(int number){
return true;
}
//案例2
public static int getMax(int a,int b){
return 100;
}
-
注意
:方法定义时return后面的返回值与方法定义上的数据类型要匹配,否则报错 -
调用格式
//格式一: 方法名(参数);
isEvenNumber(5);
//格式二: 数据类型 变量名 = 方法名(参数);
boolean flag = isEvenNumber(5);
注意
:方法的返回值通常使用变量接受(格式二),否则该返回值无意义- 案例1
public class Demo {
public static void main(String[] args) {
//1.方法名(参数);
//idEvenNumber(10); //结果为true,但无返回值
//2.数据类型 变量名= 方法名(参数);
boolean flag = idEvenNumber(10);
//boolean flag = true;
System.out.println(flag); //true
}
public static boolean idEvenNumber(int number) {
if(number%2 == 0) {
return true;
}else {
return false;
}
}
}
- 案例2:设计一个方法可以获取两个数的较大值,数据来自于参数
public class Demo {
public static void main(String[] args) {
int result = getMax(10,20);
System.out.println(result+"更大");
}
public static int getMax(int a,int b) {
if(a>b) {
return a;
}else {
return b;
}
}
}
1.4 方法的注意事项
- 1.方法不能嵌套定义
- 2.void表示无返回值,可以省略return,也可以单独写return,后面不加数据
- 3.代码到return就结束了,return后面代码无效
1.5 方法的通用格式
- 格式
public static 返回值类型 方法名(参数){
方法体;
return 数据;
}
- public static:修饰符
- 返回值类型:方法操作完毕后返回的数据的数据类型;如果方法操作完毕,没有数据返回,就写void,而且方法体中一般不写return
- 方法名:调用方法时使用的标识
- 参数:由数据类型和变量名组成,多个参数之间用逗号隔开
- return:如果方法操作完毕,有数据返回,用于把数据返回给调用者
- 定义方法时:明确返回值类型和参数
- 调用方法时
1.有void类型的方法,直接调用
2.非void类型的方法,推荐用变量接收调用
1.6 方法重载
- 概述:同一个类中,方法名相同,参数不同(类型不同/数量不同)的方法构成重载
1.6.1 案例:比较两个整数是否相同,兼容全整数类型
public class Demo {
public static void main(String[] args) {
System.out.println(compare(10,20)); //int false
System.out.println(compare((short)10,(short)20)); //short false
}
public static boolean compare(int a,int b) {
System.out.println("int");
return a==b;
}
public static boolean compare(byte a,byte b) {
System.out.println("byte");
return a==b;
}
public static boolean compare(short a,short b) {
System.out.println("short");
return a==b;
}
public static boolean compare(long a,long b) {
System.out.println("long");
return a==b;
}
}
1.7 方法的传递参数
1.7.1 方法参数传递(基本类型)
- 对于基本数据类型的参数,形式参数的改变,不影响实际参数的值
1.7.2 方法参数传递(引用类型)
- 对于引用类型的参数,形式参数的改变,影响实际参数的值
1.8 案例
1.8.1 案例:数组遍历
public class Demo {
public static void main(String[] args) {
int[] arr = {11,22,33,44,55};
printArry(arr); //[11,22,33,44,55]
}
public static void printArry(int[] arr) {
System.out.print("[");
for(int i=0;i< arr.length;i++) {
if(i == arr.length-1) { //arr.length-1取到最后一位
System.out.print(arr[i]);
}else {
System.out.print(arr[i]+", ");
}
}
System.out.print("]");
}
}
1.8.2 案例:数组最大值
public class Demo {
public static void main(String[] args) {
//1、定义数组,静态初始化
int[] arr = {11,22,33,44,55};
//3、调用方法,用变量接受返回值
int number = getMax(arr);
System.out.println(number); //55
}
//2、定义方法获取最大值
//两个明确:返回值类型:int(因为最大值)参数:int[] arr
public static int getMax(int[] arr) {
int max = arr[0];
for(int i=1;i<arr.length;i++) {
if(arr[i]>max) {
max = arr[i];
}
}
return max;
}
}
2 类和对象,封装
2.1 类的定义
- 类的组成:共同属性和行为
- 属性:在类中通过成员变量体现(类中方法外的变量)
- 行为:在类中通过成员方法体现(和前面的方法相比,去掉static关键字即可)
- 快捷键:
- 生成对象:写好
new Phone();
,按下Ctrl+alt+v自动补全前面Phone p = new Phone();
- 定义有参构造方法:按下Fn+Alt+insert:选Constructor ,按下Shift全选
- 定义成员方法:按下Fn+Alt+insert:选Getter and Setter,按下Shift全选
- 生成对象:写好
- 类的定义步骤
public class 类名{
// 成员变量
变量1的数据类型 变量1;
变量2的数据类型 变量2;
...
//成员方法
方法1;//没有static
方法2;
...
- 范例
//范例
public class Phone {
//成员变量
String brand;
int price;
//成员方法
public void call(){
System.out.println("打电话");
}
public void senMessage(){
System.out.println("发短信");
}
}
2.2 对象的使用
2.2.1 创建对象
- 格式
// 类名 对象名 = new 类名();
Phone p = new Phone();
- 快捷键:写好
new Phone();
,按下Ctrl+alt+v自动补全前面Phone p = new Phone();
2.2.2 使用对象
- 1.使用成员变量
- 格式:对象名.变量名;
- 范例:
p.brand;
- 2.使用成员方法
- 格式:对象名.方法名;
- 范例:
p.call();
public class PhoneDemo {
public static void main(String[] args) {
//创建对象:类名 变量名 = new 类名();
Phone p = new Phone();
//使用成员变量
System.out.println(p.brand); //null
System.out.println(p.price); //0
p.brand = "小米";
p.price = 2999;
System.out.println(p.brand); //小米
System.out.println(p.price); //2999
//成员方法
p.call(); //电话
p.senMessage(); //发短信
}
}
2.2.3 案例:学生
- 学生类
public class Student {
//成员变量
String name;
int age;
//成员方法
public void study(){
System.out.println("学习");
}
public void doHomeWork() {
System.out.println("做作业");
}
}
- 学生测试类
public class StudentDemo {
public static void main(String[] args) {
Student stu = new Student();
//调用成员变量
stu.name = "袁满";
stu.age = 20;
System.out.println(stu.name); //袁满
System.out.println(stu.age); //20
//调用成员方法
stu.study(); //学习
stu.doHomeWork(); //做作业
}
}
2.3 成员变量和局部变量
- 成员变量:类中方法外的变量
- 局部变量:方法中的变量
- 区别
2.4 封装
2.4.1 private( [ˈpraɪvɪt])关键字
- 是一个权限修饰符
- 可以修饰类成员(成员变量和成员方法)
- 作用是保护成员不被其他类使用,被private修饰的成员只能在本类中访问
- 针对private修饰的成员变量,如果如果需要被其他类使用,提供相应方法
- 提供“set变量名(参数)”方法,用于设置成员变量的值,方法用public修饰
- 提供“get变量名()”方法,用于获取/返回成员变量的值,方法用public修饰
public class Student {
//成员变量
String name;
private int age;
//提供get、set方法
public void setAge(int a) {
if(a<0 || a>120) {
System.out.println("你给的值有误");
}else {
age = a;
}
}
public int getAge(){
return age;
}
public void show() {
System.out.println(name+","+age);
}
}
public class StudentDemo {
public static void main(String[] args) {
//创建对象
Student stu = new Student();
//调用成员变量
stu.name = "袁满";
//stu.age = 20; //不能使用因为private
//stu.setAge(30); //袁满,30
stu.setAge(-30); //你给的值有误 袁满,0
//调用成员方法
stu.show();
}
}
2.4.2 private关键字的使用
- 一个标准类的编写:
1、把成员变量用private修饰
2、提供对应的getXxx() 和 setXxx() 方法 - 快捷键(定义成员方法):按下Fn+Alt+insert:选Getter and Setter,按下Shift全选
public class Student {
//成员变量
private String name;
private int age;
//提供get/set方法
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 show () {
System.out.println(name+"," + age);
}
}
- 测试
public class StudentDemo {
public static void main(String[] args) {
//创建对象
Student stu = new Student();
//调用成员变量
stu.setName("袁满");
stu.setAge(20);
stu.show();//袁满,20
//使用get方法获取成员变量的值
System.out.println(stu.getName()+"---"+stu.getAge()); //袁满---20
}
}
2.4.3 this关键字
- 1、this修饰的变量指代成员变量
- 方法的形参如果和成员变量同名,不带this修饰的变量值形参,而不是成员变量
- 方法的形参没有和成员变量同名,不带this修饰的变量值成员变量
- 2、什么时候使用this呢?解决局部变量隐藏成员变量的时候(同名的时候)
- 3、this:代表所在类的方法引用(方法被哪个对象调用,this就代表哪个对象)
2.4.4 封装
- 封装的原则:将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问成员变量private,提供的对应的getXxx() 和 setXxx() 方法
- 封装的好处:
1、通过方法来控制成员变量的操作,提高了代码的安全性
2、把代码用方法进行封装提高了代码的复用性
2.5 构造方法
2.5.1 构造方法定义
- 作用:创建对象
- 功能:完成对象数据初始化
- 快捷键
- 定义无参构造方法:按下Fn+Alt+insert:选Constructor ,按下C
- 定义有参构造方法:按下Fn+Alt+insert:选Constructor ,按下Shift全选
- 格式
public class 类名{
修饰符 类名(参数) { //修饰符一般使用public
}
}
//案例
public class Student {
public Student() {
//构造方法内容
}
}
- 案例
public class Student {
//成员变量
private String name;
private int age;
//构造方法
public Student() {
System.out.println("无参构造方法");
}
public void show() {
System.out.println(name+"," +age);
}
}
public class StudentDemo {
public static void main(String[] args) {
//创建对象
Student stu = new Student(); //调用的是Student类的构造方法
// 执行时机
// 1.创建对象的时候调用,每创建一次对象,就会执行一次构造方法
// 2.不能手动调用构造方法
stu.show(); //无参构造方法
//null,0
}
}
2.5.2 注意事项
-
1、如果没有定义构造方法,系统将给出一个默认的无参数构造方法
-
2、如果定义了构造方法,系统将不再提供默认的构造方法
-
解决方法:无论是否使用,都手动书写无参数构造方法,和带参数构造方法
2.5.3 案例:标准类的制作
public class Student {
//private封装成员变量
private String name;
private int age;
//无参构造方法
public Student() {
}
//有参构造方法
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//成员方法set/get
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void show() {
System.out.println(name + "," + age);
}
}
public class StudentDemo {
public static void main(String[] args) {
//1.无参构造方法创建对象,使用set方法赋值
Student stu = new Student();
stu.setName("袁满");
stu.setAge(20);
stu.show(); //袁满,20
//2.带多个参数构造方法创建对象
Student stu1 = new Student("袁满",12);
stu1.show(); //袁满,12
}
}
3 继承概述
- 继承是面向对象三个特征之一。可以使子类具有父类的属性和方法,还可以在子类重新定义,追加属性和方法。
- 继承的格式
public class 子类名 extends 父类名{}
public class Zi extends Fu{}
//Fu:是父类,也称基类、超类
//Zi:是子类,也称派生类
3.1 继承的好处
- 提高了代码的复用性(多个类相同的成员可以放到同一类中)
- 提高了代码的维护性(修改一处多处修改)
3.2 继承的弊端
- 继承让父类和子类产生了关系,当父类发生改变时子类也会改变,削弱了子类的独立性
3.3 什么时候用继承
- 继承的关系体现为包含
- 假设:我有两个A和B类,如果他们满足A是B的一种,或者B是A的一种,就说明他们存在继承关系,这个时候可以用继承了,否则就不能滥用继承
- 举例:苹果和水果、猫和动物就可以用继承;猫和狗就不行
3.3 继承中变量的访问特点
- 在子类中访问一个变量:
- 先在子类局部变量中找
- 子类成员范围中找
- 父类成员范围中找
- 如果都没有就报错(不考虑父亲的父亲)
- 范例:
- 父类
package ceshi;
public class Fu {
public int age=20;
}
- 子类
package ceshi;
public class Zi extends Fu{
public int height=175;
public int age = 30;
public void show(){
int age =40;
System.out.println(age); //40
System.out.println(height);
//System.out.println(weight); //报错
}
}
- 测试类
package ceshi;
public class Deme {
public static void main(String[] args) {
Zi z = new Zi();
z.show(); //40 175
}
}
3.4 super关键字
- super 关键字和 this 关键字用法相似
- this:代表本类对象的引用
- super:代表父类对象引用
- 案例:
- 父类
package ceshi;
public class Fu {
public int age=20;
}
- 子类
package ceshi;
public class Zi extends Fu{
public int age = 30;
public void show(){
int age =40;
System.out.println(age); //40
//1.访问本类中的成员变量age
System.out.println(this.age); //30
//2.访问父类中的成员方法
System.out.println(super.age); //20
}
}
- 测试类
package ceshi;
public class Deme {
public static void main(String[] args) {
Zi z = new Zi();
z.show(); //40 30 20
}
}
3.5 继承中构造方法的访问特点
- 子类中所有构造方法默认都会访问父类中的无参构造方法
- 为什么呢?
- 因为子类会继承父类中的数据,可能还会使用父类中的数据。所以子类初始化前,一定要完成父类初始化
- 每一个子类构造方法第一句默认都是:super();
- 如果父类有没无参构造方法,只有带参构造方法,怎么办呢
- 通过super关键字去调用带参构造方法
- 在父类自己提供一个无参构造方法(推荐使用)
- 案例:
- 父类
package ceshi;
public class Fu {
/*public Fu() {
System.out.println("Fu中无参构造方法");
}*/
public Fu(){};
public Fu(int age) {
System.out.println("Fu中带参构造方法");
}
}
- 子类
package ceshi;
public class Zi extends Fu{
public Zi() {
// super(); //默认有所以不用写
System.out.println("Zi中无参构造方法");
}
public Zi(int age) {
// super();
System.out.println("Zi中带参构造方法");
}
}
- 测试类:
package ceshi;
public class Deme {
public static void main(String[] args) {
Zi z = new Zi();
Zi z1 = new Zi(20);
/*Fu中无参构造方法
Zi中无参构造方法
Fu中无参构造方法
Zi中带参构造方法*/
}
}
3.6 继承中成员方法的访问特点
- 通过子类访问一个方法:
1.先在子类成员范围找
2.父类成员范围找
3.如果都没有报错 - 父类
package ceshi;
public class Fu {
public void show(){
System.out.println("Fu中show方法调用");
}
}
- 子类
package ceshi;
public class Zi extends Fu{
public void method() {
super.show();
System.out.println("Zi中method方法被调用");
}
}
- 测试类
package ceshi;
public class Deme {
public static void main(String[] args) {
Zi z = new Zi();
z.method();
z.show();
// z.text() //报错
/*Fu中show方法调用
Zi中method方法被调用
Fu中show方法调用*/
}
}
3.7 方法重写
- 概述:子类中出现了和父类一模一样的方法声明
- 应用:当子类需要父类的功能,而功能主体子类有自己特有的内容时,可以重写父类。沿袭父类的功能,又有自己特有的功能
- @Override:重写方法上面加上 @Override 注解,可以帮助我们检测重写方法申明的正确性
- 快捷键:在继承父类的子类中,写下父类方法名,按下回车,会自动补全重写方法体
- 范例:手机类和新手机类
- 手机类
package ceshi;
public class Phone {
public void call(String name) {
System.out.println("给"+name+"打电话");
}
}
- 新手机类
public class NewPhone extends Phone{
@Override
public void call(String name) {
System.out.println("开启视频");
// System.out.println("给"+name+"打电话");
super.call(name);
}
}
- 测试类:
package ceshi;
public class PhoneDemo {
public static void main(String[] args) {
Phone p = new Phone();
p.call("袁满"); //给袁满打电话
NewPhone n = new NewPhone();
n.call("袁满1");
/*开启视频
给袁满1打电话*/
}
}
3.8 方法重写注意事项
- 1、私有方法不能被重写,父私有成员子不能继承(private修饰的)
- 2、子类方法访问权限不能更低(public>默认>私有)
- 父类
package ceshi;
public class Fu {
private void show() {
System.out.println("Fu中show方法被调用");
}
public void method() {
System.out.println("Fu中method方法被调用");
}
}
- 子类
package ceshi;
public class Zi extends Fu{
/*@Override //报错,私有方法不能被继承
private void show() {
System.out.println("Zi中show方法被调用");
}*/
void method() { //报错,访问权限低于public,把父类public去掉就可以
System.out.println("Fu中method方法被调用");
}
}
3.9 Java中继承的注意事项
- Java中类只支持单继承(只继承一个类),不支持多继承
- Java中支持多层继承(C继承B,B继承A)
3.10 案例
- 人类:
package ceshi;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
}
- 老师类
package ceshi;
public class Teacher extends Person{
public Teacher() {};
public Teacher(String name,int age) {
/*this.name = name;
this.age = age;*/
/*super.name = name;
super.age = age;*/ //私有成员没有用
super(name,age); //通过父类的带参构造方法给成员变量赋值
}
public void teach() {
System.out.println("教学生");
}
}
- 测试类:
package ceshi;
public class Deme {
public static void main(String[] args) {
//创建无参构造方法,老师类测试
Teacher t1 = new Teacher();
t1.setName("yy");
t1.setAge(20);
System.out.println(t1.getName()+"-"+t1.getAge()); //yy-20
t1.teach(); //教学生
//带参
Teacher t2 = new Teacher("yyy",30);
System.out.println(t2.getName()+"-"+t2.getAge()); //yyy-30
t2.teach(); //教学生
}
}
4 修饰符(static关键字)
4.1 权限修饰符
4.2 状态修饰符
- final(最终态)
- static(静态)
4.2.1 final的特点
- final 关键字是最终的意思,可以修饰成员变量,成员方法,类
- final修饰的特点:
- 1.修饰方法:表示该方法是最终方法,不能被重写
- 2.修饰变量:表示该变量是常量,不能被再次赋值
- 3.修饰类:表示改类是最终类,不能被继承
- 父类:
package ceshi;
/*public class Fu {
public final void method() {
System.out.println("Fu中method方法被调用");
}
}*/
public final class Fu {
public final void method() {
System.out.println("Fu中method方法被调用");
}
}
- 子类:
package ceshi;
public class Zi extends Fu{ //报错了,不能被继承
/*@Override //因为父类method方法啊被final修饰无法重写
public void method(){
System.out.println("zi中method");
}*/
public final int age = 20;
public void show() {
// age = 100; 被final修饰为常量无法改变
System.out.println(age);
}
}
4.2.1 final修饰局部变量
- 变量是基本类型:final修饰的是基本类型的数据值,不能改变
- 变量是引用类型:final修饰的是引用类型的地址值,不能改变,但是地址里面的内容可以改变
- Student类
package ceshi;
public class Student {
public int age = 20;
}
- 测试类
package ceshi;
public class Demo {
public static void main(String[] args) {
//final修饰基本类型变量
final int age =20;
// age = 100; //final修饰后就不能重新赋值
System.out.println(age); //20
//final修饰引用类型变量
final Student s = new Student(); //final修饰的s,s的地址不能变,s.age是内容
s.age =100;
System.out.println(s.age); //100
//反证
// s = new Student(); //报错
}
}
4.2.2 static关键字
-
static关键字是静态的意思,可以修饰成员变量,成员方法
-
static修饰的特点:
- 1.被类的所有对象共享(这也是我们判断是否使用静态关键字的条件)
- 2.可以通过类名调用(推荐使用);也可以通过对象名调用
-
按照有无static修饰,成员变量和方法可以分为:
-
(一)成员变量
1、静态成员变量(类变量):有static修饰的成员变量称为静态成员变量,也叫类变量,属于类本身,直接用类名访问即可2,、实例成员变量:无static修饰的成员变量称为实例成员变量,属于类的每个对象的,必须用类的对象来访问
-
(二)成员方法
1、静态方法:有static修饰的成员方法称为静态方法,也叫类方法,属于类本身的,直接用类名访问即可2、实例方法:无static修饰的成员方法称为实例方法,属于类的每个对象的,必须用类的对象来访问
-
Student类
package ceshi;
public class Student {
public String name;
public int age;
//1: public String university;
//2
public static String university;
public void show() {
System.out.println(name+","+age+","+university);
}
}
- 测试类:
package ceshi;
public class StaticDemo {
public static void main(String[] args) {
//2:被static修饰的变量,推荐用类名访问
Student.university="清华大学";
Student s = new Student();
s.name = "yy";
s.age = 20;
//1 s.university = "清华大学";
s.show(); //yy,20,清华大学
Student s1 = new Student();
s1.name = "yy1";
s1.age = 30;
s1.show(); //1: yy1,30,null
//2: yy1,30,清华大学
}
}
4.2.2 static 访问特点
非静态的成员方法
●能访问静态的成员变量
●能访问非静态的成员变量
●能访问静态的成员方法
●能访问非静态的成员方法
静态的成员方法
●能访问静态的成员变量
●能访问静态的成员方法
总结成一句话就是:静态成员方法只能访问静态成员
- 范例:
package ceshi;
public class Student {
//非静态成员变量
public String name = "yy";
//静态成员变量
public static String university = "清华大学";
//非静态成员方法
public void show1() {
}
public void show2() {
System.out.println(name);
System.out.println(university);
show1();
show3();
}
//静态成员方法
public static void show3() {
}
public static void show4() {
// System.out.println(name); 访问非静态成员变量报错
System.out.println(university);
// show1(); 访问非静态成员方法报错
show3();
}
}
5 多态
5.1 多态概述
- 同一个对象,不同时刻表现出来的不同形态
- 多态的分类:具体类多态、抽象类多态、接口多态
- 多态的前提和体现
- 1,有继承/实现关系
- 2,有方法重写
- 3,有父类引用指向子类对象
- 父类
package ceshi;
public class Animal {
public void eat(){
System.out.println("吃东西");
}
}
- 子类
package ceshi;
public class Cat extends Animal{ //1,有继承/实现关系
//2,有方法重写
@Override
public void eat() { //重写快捷方法直接写eat按回车自动生成
System.out.println("猫吃东西");
}
}
- 测试类
package ceshi;
public class Demo {
public static void main(String[] args) {
//3、有父类引用指向子类对象
Animal a = new Cat();
}
}
5.2 多态中成员访问特点
- 成员变量:编译看左边,运行看左边
- 成员方法:编译看左边,运行看右边
- 为什么成员方法和成员变量的访问不一样呢?
因为成员方法有重写而成员变量没有重写(还是父类的) - 父类
package ceshi;
public class Animal {
public int age = 20;
public void eat(){
System.out.println("动物吃东西");
}
}
- 子类
package ceshi;
public class Cat extends Animal{ //1,有继承/实现关系
//2,有方法重写
public int age = 40;
public int weight = 10;
@Override
public void eat() { //3,重写快捷方法直接写eat按回车自动生成
System.out.println("猫吃东西");
}
public void playGame(){
System.out.println("猫玩捉迷藏");
}
}
- 测试:
package ceshi;
public class Demo {
public static void main(String[] args) {
//有父类引用指向子类对象
Animal a = new Cat();
a.eat(); //猫吃东西
//对于方法的调用: 编译(写代码)看左边Animal,运行看右边 Cat
//看左边指的是看等号的左边,等号左边是Animal,会找Animal里面的eat方法,有方法才不报错
//运行的时候看等号的右边,等号右边是Cat,执行Cat里面的eat方法
// a.playGame; 报错,父类有没这个方法
System.out.println(a.age); //20;对于变量的调用: 编译看左边,运行看左边
// System.out.println(a.weight); 报错
}
}
5.3 多态的好处和弊端
- 好处:提高程序的扩展性
- 具体体现:定义方法时,使用父类作为参数,将来在使用的时候,使用具体的子类参与操作
- 弊端:不能使用子类的特有功能
5.3 多态中的转型
- 向上转型:从子到父,父类引用指向子类对象
- 向下转型:从父到子,父类引用转为子类对象
- 转型的好处:可以使用子类的特有功能
- 父类:
package ceshi;
public class Animal {
public void eat(){
System.out.println("动物吃东西");
}
}
- 子类:
package ceshi;
public class Cat extends Animal{ //1,有继承/实现关系
//2,有方法重写
@Override
public void eat() { //重写快捷方法直接写eat按回车自动生成
System.out.println("猫吃东西");
}
public void playGame(){
System.out.println("猫玩捉迷藏");
}
}
- 测试:
package ceshi;
public class Demo {
public static void main(String[] args) {
//多态
Animal a = new Cat(); //向上转型
a.eat();
// a.playGame(); 报错,因为编译看左边Animal中没有这个方法
//向下转型
Cat c = (Cat)a;
c.eat(); //猫吃东西
c.playGame(); //猫玩捉迷藏
}
}
6 抽象类
6.1 抽象类概述
- 在Java中,一个没有方法体的方法应该定义为抽象方法,如果类中有抽象方法,该类必须定义为抽象类
6.2 抽象类的特点
- 1,抽象类和抽象方法必须使用 abstract ([æbˈstrækt])关键字修饰
public abstract class 类名(){
public abstract void 方法名();
}
- 2,抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
- 3,抽象类不能实例化,但是可以参照多态的方式,通过子类对象实例化,这叫抽象类多态
- 4,抽象类的子类要么重写所有抽象方法,要么它本身就是一个抽象类
6.3 抽象类成员特点
- 成员变量:可以是变量,可以是常量
- 构造方法:有构造方法但是本身不能实例化,用于子类访问父类数据初始化(多态的方式实例化)
- 成员方法:
1,可以是抽象方法,限定子类必须重写
2,还可以上非抽象方法,提高代码的复用性 - 案例:
package ceshi;
public abstract class Animal {
private int age = 20;
private final String name = "yy";
public Animal(){};
public Animal(int age) {
this.age = age;
}
public void show() {
System.out.println(age);
System.out.println(name);
}
public abstract void eat();
}
6.4 案例
- 父类
package ceshi;
public abstract class Animal {
private String name;
private int age;
public Animal() { }
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
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 abstract void eat();
}
- 子类
package ceshi;
public class Cat extends Animal{ //1,有继承/实现关系
public Cat() { }
public Cat(String name, int age) {
super(name, age);
}
//2,有方法重写
@Override
public void eat() { //3,重写快捷方法直接写eat按回车自动生成
System.out.println("猫吃东西");
}
}
- 测试
package ceshi;
public class Demo {
public static void main(String[] args) {
//多态
Animal a = new Cat(); //调用无参构造方法
a.setName("加菲猫");
a.setAge(20);
System.out.println(a.getName()+","+a.getAge()); //加菲猫,20
a.eat(); //猫吃东西
//带参
a = new Cat("加菲猫1",20);
System.out.println(a.getName()+","+a.getAge()); //加菲猫1,20
a.eat(); //猫吃东西
}
}
7 接口
7.1 接口的概述
- 接口就是一种公共规范的标准,只要符合规范大家都可以用
- Java中的接口体现在对行为的抽象
7.2 接口的特点
- 1、接口用关键字 interface 修饰
public interface 接口名 {}
- 2、类实现接口用 implements ([ˈɪmplɪments] )表示
public class 类名 implement 接口名 {}
- 3、接口不能实例化,参照多态的方式,通过实现类对象实例化,这叫接口多态
- 4、接口的实现类:要么重写接口中所有抽象方法,要么是抽象类
7.3 接口成员的特点
- 1、成员变量:只能是常量,默认修饰符:public static final
- 2、接口中没有构造方法,因为接口中主要是对行为进行抽象的,是没有具体存在
(如果 一个类没有父类,会默认继承Object类,Object类只有无参构造方法) - 3、成员方法:只能是抽象方法,默认修饰符:public abstract
- 范例
package ceshi;
public interface Inter {
//1,默认带有public static final
public int num1 = 10;
public static final int num2 = 20;
int num3 = 30;
//2,报错,接口中没有构造方法
// public Inter(); 报错
//3,接口中必须是抽象方法
public abstract void mehtod();
// public void mehtod(){}; 报错
void show(); //默认带有public abstract
}
7.4 案例
- 接口
package ceshi;
public interface Inter {
void jump();
}
- 父类
package ceshi;
public abstract class Animal {
private String name;
private int age;
public Animal() { }
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
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 abstract void eat();
}
- 子类
package ceshi;
public class Cat extends Animal implements Jumpping{ //2,接口不能继承,类用implement实现接口,该类为实现类
public Cat() { }
public Cat(String name, int age) {
super(name, age);
}
@Override
public void jump() {
System.out.println("猫跳高");
}
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
- 测试
package ceshi;
public class Demo {
public static void main(String[] args) {
Jumpping j = new Cat();
j.jump(); //只有调接口的
Animal a = new Cat("加菲猫",5);
System.out.println(a.getName()+","+a.getAge());
a.eat();
// a.jump(); 报错,无法调用接口的
//推荐使用子类对象,子类中功能最多
Cat c = new Cat();
c.eat();
c.jump();
c.setName("加菲猫");
c.setAge(20);
}
}
7.5 类和接口的关系
- 类和类的关系:继承关系只能单继承,但是可以多层继承
- 类和接口的关系:实现关系,可以单实现,也可以多实现还可以继承一个类的同时实现多个接口
public class IterImpl extends Object implements Inter1,Inter2,Inter3 {}
- 接口和接口的关系:继承关系,可以单继承,可以多继承
//单继承
public interface Inter3 extends Inter1 {}
//多继承
public interface Inter3 extends Inter1,Inter2 {}
7.6 抽象类和接口的区别
- 成员区别
抽象类:变量、常量;有构造方法;有抽象方法,也有非抽象方法
接口:常量;抽象方法 - 关系区别
类与类:继承,单继承
类与接口:实现,可以单实现,也可以多实现
接口与接口:继承,单继承,多继承 - 设计理念区别
抽象类:对类抽象,包括属性和行为
接口:对行为抽象,主要是行为 - 范例:
7.7 案例思路
8 形参和返回值
8.1 类名作为形参和返回值
- 类名作为形参,需要的是该类的对象
- 类名作为返回值,返回值的是该类的对象
- Cat类
package ceshi;
public class Cat{
public void eat() {
System.out.println("猫吃鱼");
}
}
- Cat操作类
package ceshi;
public class CatOperator {
public void useCat(Cat c) { //类名作为形参需要的是一个Cat对象,Cat c = new Cat();
c.eat();
}
//Cat作为返回值
public Cat getCat() {
Cat c = new Cat();
return c;
}
}
- 测试类
package ceshi;
public class Demo {
public static void main(String[] args) {
//创建操作类对象,调用方法
CatOperator co = new CatOperator();
Cat c1 = new Cat();
co.useCat(c1); //需要一个Cat对象,上面创建Cat对象;猫吃鱼
Cat c2 = co.getCat(); //调用getCat方法,把new Cat()赋值给c2
c2.eat(); //猫吃鱼
}
}
8.2 抽象类名作为形参和返回值
- 抽象类名作为形参,需要的是该类的子类对象
- 抽象类名作为返回值,返回值的是该类的子类对象
- 父类
package ceshi;
public abstract class Animal {
public abstract void eat();
}
- 子类
package ceshi;
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
- 操作类
package ceshi;
public class AnimalOperator {
public void useAnimal(Animal a) { //需要的是Animal的子类对象 Animal a = new Cat();
a.eat();
}
public Animal getAnimal() {
Animal a = new Cat();
return a;
}
}
- 测试类
package ceshi;
public class Demo {
public static void main(String[] args) {
//创建操作类对象,调用方法
AnimalOperator ao = new AnimalOperator();
Animal a = new Cat();
ao.useAnimal(a);
a.eat();
Animal a2 = ao.getAnimal(); //new Cat()
a2.eat();
}
}
8.3 接口名作为形参和返回值
- 接口名作为形参,需要的是该类的实现类对象
- 接口名作为返回值,返回值的是该类的实现类对象
- 接口
package ceshi;
public interface Jumpping {
void jump();
}
- 实现类
package ceshi;
public class Cat implements Jumpping{
@Override
public void jump() {
System.out.println("猫可以跳高");
}
}
- 接口操作类
package ceshi;
public class JumppingOperator {
public void useJumpping(Jumpping j) { //需要的是接口实现类,Jumpping j = new Cat();
j.jump();
}
public Jumpping getJumpping() {
Jumpping j = new Cat();
return j;
}
}
- 测试类
package ceshi;
public class Demo {
public static void main(String[] args) {
//创建操作类对象,调用方法
JumppingOperator jo = new JumppingOperator();
Jumpping j = new Cat();
jo.useJumpping(j); //猫可以跳高
Jumpping j2 = jo.getJumpping();
j2.jump(); //猫可以跳高
}
}
9 内部类
9.1 内部类的概述
- 1、内部类就是在一个类中定义的类
- 2、格式
public class 类名 {
修饰符 class 类名 {
}
}
- 3、内部类访问特点
1,内部类可以直击访问外部的成员,包括私有
2,外部内访问内部类的成员必须创建内部类对象,通过对象来调用内部类成员
package ceshi;
public class Outer {
private int num = 20;
public class Inter {
public void show() {
System.out.println(num); //可以访问外部类私有
}
}
public void method() {
// show(); 报错,不能直接访问需要创建内部类对象
Inter i = new Inter();
i.show();
}
}
- 4、内部类的分类
1.成员内部类 (实例内部类)
2.局部内部类(类方法中定义的类)
3. 匿名内部类 (重点)
9.2 成员内部类(了解)
- 成员内部类外界如何创建对象使用?
格式:外部类名.内部类名 对象名 = new 外部类对象.内部类对象();
范例:Outer.Inter oi = new Outer(). new Inter();
- 思路
1、内部类通常用private修饰
2、通过外部类创建内部类对象,调用内部类方法
3、其他类创建外部类对象调用method方法 - 案例
package ceshi;
public class Outer {
private int num = 20;
//测试1
/*public class Inter {
public void show() {
System.out.println(num); //可以访问外部类私有
}
}*/
//一、内部类通常用private修饰;二、通过外部类创建内部类对象,调用内部类方法;三、外部创建外部类对象调用method方法
private class Inter {
public void show() {
System.out.println(num);
}
}
//二、通过外部类创建内部类对象,调用内部类方法
public void method() {
Inter i = new Inter();
i.show();
}
}
- 测试
package ceshi;
public class InterDemo {
public static void main(String[] args) {
//创建内部类对象,并调用方法
// Inter i = new Inter(); 报错
//测试1
// Outer.Inter oi = new Outer(). new Inter();
// oi.show(); //20
//三、外部创建外部类对象调用method方法
Outer o = new Outer();
o.method(); //20
}
}
9.3 局部内部类(了解)
- 局部内部类是在方法中定义的类,所以外界是无法直接使用,需要在方法内部创建对象并使用
- 该类可以直接访问外部类的成员,也可以访问方法内的局部变量
- 范例
package ceshi;
public class Outer {
private int num1 = 10;
public void method() {
int num2 = 20;
//局部内部类
class Inter {
public void show() {
System.out.println(num1);
System.out.println(num2);
}
}
//需要在方法中创建局部内部类对象,调用方法,否则没法访问
Inter i = new Inter();
i.show();
}
}
- 测试
package ceshi;
public class InterDemo {
public static void main(String[] args) {
Outer o = new Outer();
o.method(); //10
//20
}
}
9.4 匿名内部类(重点)
- 前提:存在一个类或者接口,这里的类可以是抽象类、具体类
- 好处:可以少写接口实现类
- 格式
new 类名或者接口名() {
重写方法
};
- 本质是继承了该类或实现该接口的子类匿名对象
- 范例
package ceshi;
public class Outer {
private int num1 = 10;
public void method() {
//只能调用一次
/*new Inter() {
@Override
public void show() {
System.out.println("匿名内部类");
}
}.show(); //前面为一个对象,调用里面show()方法*/
//赋值给对象可以多次调用
Inter i = new Inter() {
@Override
public void show() {
System.out.println("匿名内部类");
}
};
i.show();
i.show();
}
}
- 接口
package ceshi;
public interface Inter {
void show();
}
- 测试
package ceshi;
public class InterDemo {
public static void main(String[] args) {
Outer o = new Outer();
o.method(); //匿名内部类
//匿名内部类
}
}
- 匿名内部类在开发中的使用
- 测试类
package ceshi;
public class JumppingDemo {
public static void main(String[] args) {
//创建接口操作类对象,调用method方法
JumppingOperator jo = new JumppingOperator();
//不用创建接口实现类
jo.method(new Jumpping() {
@Override
public void jump() {
System.out.println("猫跳高"); //猫跳高
}
});
jo.method(new Jumpping() {
@Override
public void jump() {
System.out.println("狗跳高"); //狗跳高
}
});
}
}