static: 表示静态,是 Java 中的一个修饰符,可以修饰成员方法,成员变量
静态的,意味着可以共享
被 static 修饰的成员变量,叫做静态变量
特点:
调用方式:
静态变量是随着类的加载而加载的,优先于对象出现的
被 static 修饰的成员方法,叫做静态方法
特点:
调用方式:
工具类
帮助我们做一些事情的,但是不描述任何事情的类,叫做工具类
工具类书写规则:
类名见名知意
私有化构造方法
public class ArrUtil{
//私有构造方法
private ArrUtil(){}
}
构造方法一旦私有,在外界就无法创建这个类的对象。
由于测试类不描述任何事物,所以创建其对象也毫无意义。
方法定义为静态
public class ArrUtil{
//私有构造方法
private ArrUtil(){}
//方法定义为静态
public static int getMax(...){...}
public static int getMin(...){...}
public static int getSum(...){...}
public static int getAvg(...){...}
}
工具类中的方法在测试类调用格式:
练习:定义数组工具类
需求:在实际开发中,经常会遇到一些数组使用的工具类。
请按照如下要求编写一个数组的工具类:ArrayUtil
提供一个工具类方法printArr , 用于返回整数数组的内容。
返回的字符串格式如:[10,20,50,34,100] (只考虑整数数组,且只考虑一维数组)
提供这样一个工具方法 getAerage ,用于返回平均分。(只考虑浮点型数组,且只考虑一维数组)
定义一个测试类TestDemo,调用该工具类的工具方法,并返回结果。
package Just.a02staticdemo2;
public class ArrayUtil {
//私有化构造方法
//目的:不让外界创建他的对象
private ArrayUtil(){}
//定义printArr,用于返回整数数组的内容
public static String printArr(int[] arr){
//定义一个 StringBuilder 类的对象,用来拼接数组
StringBuilder sb = new StringBuilder();
sb.append("[");
//for 循环遍历数组
for (int i = 0; i < arr.length; i++) {
//i 索引 arr[i] 数组元素
if(i == arr.length - 1){
sb.append(arr[i]);
}else{
sb.append(arr[i]).append(",");
}
}
sb.append("]");
//把 StringBuilder 类型转换成 String 类型并返回
return sb.toString();
}
//定义getAerage函数,用于返回平均值
public static double getAerage(double[] arr){
//定义变量,用来获取数组元素的总和
double sum = 0;
//for循环遍历数组
for (int i = 0; i < arr.length; i++) {
sum = sum + arr[i];
}
//定义变量,用来接收平均值
double average = sum/arr.length;
//返回平均值
return average;
}
}
===========================================================================================
package Just.a02staticdemo2;
public class TestDemo {
public static void main(String[] args) {
//测试工具类中的两个方法是否正确
int[] arr1 = {1,2,3,4,5};
String str = ArrayUtil.printArr(arr1);
System.out.println(str);
double[] arr2 = {1.5,3.7,4.9,5.8,6.6};
double avg = ArrayUtil.getAerage(arr2);
System.out.println(avg);
}
}
============================================================================================
运行结果:
[1,2,3,4,5]
4.5
练习:定义学生工具类
需求:定义一个集合,用于存储3个学生对象。
学生类的属性为:name 、age、gender
定义一个工具类,用于获取集合中最大学生的年龄
package Just.a03staticdemo3;
public class Student {
//定义私有化成员变量 姓名、年龄、性别
private String name;
private int age;
private String gender;
//无参构造函数
public Student() {
}
//有参构造函数
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
//获取
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 getGender() {
return gender;
}
//设置
public void setGender(String gender) {
this.gender = gender;
}
}
=======================================================================================================
package Just.a03staticdemo3;
import java.util.ArrayList;
public class StudentTest {
public static void main(String[] args) {
//定义集合用来存储3个学生对象
ArrayList list = new ArrayList<>();
//创建三个学生对象
Student stu1 = new Student("鑫鑫",21,"女");
Student stu2 = new Student("肉墩",22,"女");
Student stu3 = new Student("几坨",23,"男");
//把创建的学生对象添加到集合中
list.add(stu1);
list.add(stu2);
list.add(stu3);
//调用工具类中的函数,用来返回集合中最大学生的年龄
int maxAge = StudentUtil.getMaxAge(list);
System.out.println("输出集合中最大学生的年龄:");
System.out.println(maxAge);
}
}
=============================================================================================================
package Just.a03staticdemo3;
import java.util.ArrayList;
public class StudentUtil {
//定义私有化构造函数
private StudentUtil(){}
//定义方法,获取集合中最大学生的年龄
public static int getMaxAge(ArrayList list){
//定义变量,用来记录学生中的最大年龄
int maxAge = list.get(0).getAge();
//for循环遍历集合中的对象及对象的年龄
for (int i = 0; i < list.size(); i++) {
//获取集合中的对象
Student stu = list.get(i);
//获取对象的年龄
int age = stu.getAge();
//把学生中最大学生的年龄赋值给 maxAge
if(maxAge < age){
maxAge = age;
}
}
return maxAge;
}
}
=======================================================================================================
运行结果:
输出集合中最大学生的年龄:
23
static 的注意事项:
**静态:**随着类的加载而加载
**非静态:**跟对象有关
public: 被 JVM 调用,访问权限足够大
static: 被 JVM 调用,不用创建对象,直接类名访问
因为 main 方法是静态的,所以测试类中其他方法也需要是静态的
void: 被 JVM 调用,不需要给 JVM 返回值
main: 一个通用的名称,虽然不是关键字,但是被 JVM 识别
String[] args: 以前用于接收键盘录入数据的,现在没用
继承是面向对象三大特征之一,可以让类跟子类之间产生子父的关系。
Java 中提供一个关键字 extends ,用这个关键字,我们可以让一个类和另一个类建立起继承关系。
public class Student extends Person { }
Student 称为子类 ( 派生类 ) ,Person 称为父类 ( 基类或超类 )。
当类与类之间,存在相同 (共性)的内容,并满足子类是父类中的一种,就可以考虑使用继承,来优化代码。
Java 只支持单继承,不支持多继承,但支持多层继承。
**单继承:**一个子类只能继承一个父类
**不支持多继承:**子类不能同时继承多个父类
**多层继承:**子类 A 继承父类 B ,父类 B 可以继承父类 C
每一个类都直接或间接的继承于 Object
**注意:**子类只能访问父类中非私有的成员
**画图法:**从下往上画
下面:子类
上面:父类
需要把子类中的共性内容抽取到父类中
核心:
1、共性内容抽取
2、子类是父类中的一种
书写代码:
从上往下
( 自己设计一个继承体系 )
现在有四种动物:布偶猫、中国狸花猫、哈士奇、泰迪
暂时不考虑属性,只要考虑行为。
请按照继承的思想特点进行继承体系的设计。
四种动物分别有以下的行为:
package Just.a01oopextendsdemo1;
public class Animal {
//注意事项:
//子类只能访问父类中非私有的成员
//吃饭
public void eat(){
System.out.println("吃东西");
}
//喝水
public void drink(){
System.out.println("喝水");
}
}
=================================================
package Just.a01oopextendsdemo1;
public class Cat extends Animal{
//抓老鼠
public void catMouse(){
System.out.println("抓老鼠");
}
}
==================================================
package Just.a01oopextendsdemo1;
public class Dog extends Animal{
//看家
public void lookHome(){
System.out.println("狗看家");
}
}
===================================================
package Just.a01oopextendsdemo1;
public class Ragdoll extends Cat{
}
==================================================
package Just.a01oopextendsdemo1;
public class LiHua extends Cat{
}
====================================================
package Just.a01oopextendsdemo1;
public class Husky extends Dog{
public void breakHome(){
System.out.println("哈士奇在拆家");
}
}
=====================================================
package Just.a01oopextendsdemo1;
public class Teddy extends Dog{
public void touch(){
System.out.println("泰迪又在曾我的腿~");
}
}
======================================================
package Just.a01oopextendsdemo1;
public class Test {
public static void main(String[] args) {
//创建对象并调用方法
//1、创建布偶猫的对象
Ragdoll rd = new Ragdoll();
rd.eat();
rd.drink();
rd.catMouse();
System.out.println("---------------------");
//2、创建哈士奇的对象
Husky h = new Husky();
h.eat();
h.drink();
h.lookHome();
h.breakHome();
}
}
========================================================
运行结果:
吃东西
喝水
抓老鼠
---------------------
吃东西
喝水
狗看家
哈士奇在拆家
父类中的内容 | 父类中的权限 | 子类继承情况 | 父类中的权限 | 子类继承情况 | 说明 |
---|---|---|---|---|---|
构造方法 | 非私有 | 不能继承 | 私有 | 不能继承 | 父类的构造方法不能被子类继承 |
成员变量 | 非私有 | 能继承 | 私有 | 能继承 | 子类虽然可以继承父类私有成员变量,但是不能调用 |
成员方法 | 非私有 | 能继承 | 私有 | 不能继承 | 只有父类中的虚方法,才能被子类继承 |
虚方法表:
继承中成员变量访问特点:就近原则,谁离我近,我就用谁
先在局部位置找 ——> 本类成员位置找 ——> 父类成员位置找 ——> 逐级往上。
如果遇到重名:
System.out.println(name); <——> 从局部位置开始往上找
System.out.println(name); <——> 从本类成员位置开始往上找
System.out.println(name); <——> 从父类成员位置开始往上找
package Just.a05oopextendsdemo5;
//测试类
public class Test {
public static void main(String[] args) {
Zi z = new Zi();
z.ziShow();
}
}
//父类
class Fu{
String name = "Fu";
}
//子类
class Zi extends Fu{
String name = "Zi";
public void ziShow(){
String name = "ziShow";
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
}
}
=======================================================================
运行结果:
ziShow
Zi
Fu
直接调用满足就近原则:谁离我近,我就用谁
this调用:就近原则
super调用,直接访问父类
应用场景:
当父类的方法不能满足子类现在的需求时,需要进行方法重写
书写格式:
在继承体系中,子类出现了和父类一模一样的方法声明,我们就称子类这个方法是重写的方法。
@Override重写注释:
1、@Override 是放在重写后的方法上,校验子类重写时语法是否正确。
2、加上注释后如果有红色波浪线,表示语法错误。
3、建议重写方法都加@Override注解,代码安全,优雅!
package Just.a06oopextendsdemo6;
public class Test {
public static void main(String[] args) {
Student stu = new Student();
stu.lunch();
}
}
//父类
class Person{
public void eat(){
System.out.println("吃米饭、吃菜");
}
public void drink(){
System.out.println("喝开水");
}
}
//子类
class Student extends Person{
@Override
public void eat(){
System.out.println("吃意大利面");
}
@Override
public void drink(){
System.out.println("喝凉水");
}
public void lunch(){
this.eat();
this.drink();
super.eat();
super.drink();
}
}
==================================================================
运行结果:
吃意大利面
喝凉水
吃米饭、吃菜
喝开水
子类覆盖了从父类继承下来的虚方法表中的方法
方法从写注意事项和要求
1、重写方法的名称、形参列表必须与父类中的一致
2、子类重写父类方法时,访问权限子类必须大于等与父类( 暂时了解 :空着不写 < protected < public )
3、子类重写父类方法时,返回值类型子类必须小于等于父类
4、建议:重写的方法尽量和父类保持一致
5、只有被添加到虚方法列表中的方法才能被重写
现在有三种动物:哈士奇、沙皮狗、中华田园犬
暂时不考虑属性,只考虑行为。
请按照继承的思想特点进行继承体系的设计。
三种动物分别有以下的行为:
package Just.a07oopextendsdemo7;
public class Dog {
//吃饭
public void eat(){
System.out.println("吃狗粮");
}
//喝水
public void water(){
System.out.println("喝水");
}
//看家
public void seeHome(){
System.out.println("看家");
}
}
=============================================================
package Just.a07oopextendsdemo7;
public class Husky extends Dog{
//拆家
public void breakHome(){
System.out.println("拆家");
}
}
=============================================================
package Just.a07oopextendsdemo7;
public class SharPei extends Dog{
//父类中的方法不能满足我们的需求了,所以需要进行重写
@Override
public void eat(){
//吃狗粮直接可以调用父类中的方法
super.eat();
System.out.println("吃骨头");
}
}
===============================================================
package Just.a07oopextendsdemo7;
public class ChineseRuralDog extends Dog{
//父类中的方法不能满足我们的需求了,所以需要进行重写
@Override
public void eat(){
System.out.println("吃剩饭");
}
}
===============================================================
package Just.a07oopextendsdemo7;
public class DogTest {
public static void main(String[] args) {
//创建对象并调用
Husky h = new Husky();
h.eat();
h.water();
h.seeHome();
h.breakHome();
ChineseRuralDog cd = new ChineseRuralDog();
cd.eat();
cd.water();
cd.seeHome();
}
}
================================================================
运行结果:
吃狗粮
喝水
看家
拆家
吃剩饭
喝水
看家
package Just.a08oopextendsdemo08;
public class Person {
String name;
int age;
//无参构造
public Person() {
System.out.println("父类的无参构造");
}
//有参构造
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
=======================================================================
package Just.a08oopextendsdemo08;
public class Student extends Person{
public Student(){
//子类构造方法中隐藏的 super() 去访问父类的无参构造
super();//==此super方法可以省略==
System.out.println("子类的无参构造");
}
//调用父类中的有参构造
public Student(String name,int age){
super(name,age);
}
}
========================================================================
package Just.a08oopextendsdemo08;
public class Test {
public static void main(String[] args) {
//创建学生对象
Student stu1 = new Student();
Student stu2 = new Student("zhangsan",23);
System.out.println(stu2.name + "、" +stu2.age);
}
}
=========================================================================
父类的无参构造
子类的无参构造
zhangsan、23
继承中构造方法的访问特点是什么?
关键字 | 访问成员变量 | 访问成员方法 | 访问构造方法 |
---|---|---|---|
this | this. 成员变量 访问本类成员变量 |
this. 成员方法(…) 访问本类成员方法 |
this(…) 访问本类其他构造方法 |
super | super. 成员变量 访问父类成员变量 |
super. 成员方法(…) 访问父类成员方法 |
super(…) 访问父类构造方法 |
**this(…) 访问其他构造方法举例 **
package Just.a09oopextendsdemo09;
public class Student {
String name;
int age;
String school;
/*
需求:默认大学名为 “传智大学”
利用:this 调用本类中的其他构造
*/
public Student() {
/*
this() 调用本类其他构造方法
细节:虚拟机就不会再添加super();
其他语句写在this()下面
*/
this(null,0,"传智大学");
}
public Student(String name, int age, String school) {
this.name = name;
this.age = age;
this.school = school;
}
}
======================================================================
package Just.a09oopextendsdemo09;
public class Test {
public static void main(String[] args) {
Student stu = new Student();
System.out.println(stu.school);
}
}
======================================================================
传智大学
带有继承结构的标准 Javabean 类
1、经理
成员变量:工号、姓名、工资、管理奖金
成员方法:工作(管理其他人)、吃饭(吃米饭)
2、厨师
成员变量:工号、姓名、工资
成员方法:工作(炒菜)、吃饭(吃米饭)
package Just.a10oopextendsdemo10;
public class Employee {
//工号
private String id;
//姓名
private String name;
//工资
private double salary;
//无参构造
public Employee() {
}
//有参构造
public Employee(String id, String name, double salary) {
this.id = id;
this.name = name;
this.salary = salary;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
//工作
public void work(){
System.out.println("员工在工作");
}
//吃饭
public void eat(){
System.out.println("吃米饭");
}
}
======================================================================================
package Just.a10oopextendsdemo10;
public class Manager extends Employee{
//管理奖金
private double bonus;
//空参构造
public Manager(double bonus) {
}
//带全部参数的构造
//父类 + 子类
public Manager(String id, String name, double salary, double bonus) {
//父类有参构造
super(id, name, salary);
this.bonus = bonus;
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
@Override
public void work() {
System.out.println("管理其他人");
}
}
========================================================================================
package Just.a10oopextendsdemo10;
public class Cook extends Employee{
public Cook() {
}
public Cook(String id, String name, double salary) {
//父类有参构造
super(id, name, salary);
}
@Override
public void work() {
System.out.println("厨师正在炒菜");
}
}
=======================================================================================
package Just.a10oopextendsdemo10;
public class Test {
public static void main(String[] args) {
//创建对象并赋值调用
Manager m = new Manager("001","张三",15000,8000);
System.out.println(m.getId() + "," + m.getName() + "," + m.getSalary() + "," + m.getBonus());
m.work();
m.eat();
System.out.println();
Cook c = new Cook();
c.setId("002");
c.setName("李四");
c.setSalary(10000);
System.out.println(c.getId() + "," + c.getName() + "," + c.getSalary());
c.work();
c.eat();
}
}
=========================================================================================
001,张三,15000.0,8000.0
管理其他人
吃米饭
002,李四,10000.0
厨师正在炒菜
吃米饭
面向对象三大特征之一
什么是多态?
同类型的对象,表现出的不同形态。
多态的表现形式:
父类类型 对象名称 = 子类对象 ;
多态的前提:
多态的好处?
使用父类型作为参数,可以接收所有子类对象,
体现多态的扩展性与便利
package Just.a01polymorphismdemo1;
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;
}
public void show(){
System.out.println(name + "," + age);
}
}
====================================================================
package Just.a01polymorphismdemo1;
public class Student extends Person{
@Override
public void show() {
System.out.println("学生的信息为:" + getName() + "," +getAge());
}
}
====================================================================
package Just.a01polymorphismdemo1;
public class Teacher extends Person{
@Override
public void show() {
System.out.println("老师的信息为:" + getName() + "," +getAge());
}
}
====================================================================
package Just.a01polymorphismdemo1;
public class Administrator extends Person{
@Override
public void show() {
System.out.println("管理员的信息为:" + getName() + "," +getAge());
}
}
====================================================================
package Just.a01polymorphismdemo1;
public class Test {
public static void main(String[] args) {
//创建三个对象,并调用register方法
Student stu = new Student();
stu.setName("张三");
stu.setAge(18);
Teacher t = new Teacher();
t.setName("王建国");
t.setAge(30);
Administrator admin = new Administrator();
admin.setName("管理员");
admin.setAge(35);
//调用register方法
register(stu);
register(t);
register(admin);
}
//这个方法既能接收老师、又能接收学生,还能接收管理员
//只能把参数写成这三个类型的父亲
//多态的运用
public static void register(Person p){
p.show();
}
}
====================================================================
学生的信息为:张三,18
老师的信息为:王建国,30
管理员的信息为:管理员,35
调用成员变量:编译看左边,运行也看左边。
Animal a = new Dog();
/*
调用成员变量:编译看左边,运行也看左边(看左边:定义对象时等号左边的类)
编译看左边:javac编译代码的时候,会看左边的父类中有没有这个变量,如果有,编译成功,如果没有编译失败。
运行也看左边:java运行代码的时候,实际获取的就是左边父类中的成员变量的值
*/
调用成员方法:编译看左边,运行看右边。
Animal a = new Dog();
/*
编译成员方法:编译看左边,运行看右边(看左边:定义对象时等号左边的类。看右边:定义对象时等号右边的类)
编译看左边:javac编译代码的时候,会看左边父类中有没有这个方法,如果有,编译成功,如果没有编译失败
**运行看右边:**java运行代码的时候,实际上运行的是子类中的方法
*/
理解:
Animal a = new Dog();
/*
现在用 a 去调用变量和方法
而 a 是 Animal 类型的,所以默认都会从 Animal 这个类中去找
成员变量:在子类的对象中,会把父类的成员变量也继承下来
成员方法:如果子类对方法进行了重写,那么在虚方法表中时会把父类的方法进行覆盖的。
*/
多态调用成员的内存图解
package Just.a02polymorphismdemo2;
public class test {
public static void main(String[] args) {
//创建对象(多态式)
// Fu f = new Zi();
Animal a = new Dog();
/*
调用成员变量:编译看左边,运行也看左边(看左边:定义对象时等号左边的类)
编译看左边:javac编译代码的时候,会看左边的父类中有没有这个变量,如果有,编译成功,如果没有编译失败。
运行也看左边:java运行代码的时候,实际获取的就是左边父类中的成员变量的值
*/
System.out.println(a.name);//结果:Animal 类中,name 变量的值 —— 动物
/*
编译成员方法:编译看左边,运行看右边(看左边:定义对象时等号左边的类。看右边:定义对象时等号右边的类)
编译看左边:javac编译代码的时候,会看左边父类中有没有这个方法,如果有,编译成功,如果没有编译失败
运行看右边:java运行代码的时候,实际上运行的是子类中的方法
*/
a.show();//结果:运行 Dog 类中的show()方法,输出————Dog --- show方法
}
}
class Animal{
String name = "动物";
public void show(){
System.out.println("Animal --- show方法");
}
}
class Dog extends Animal{
String name = "狗";
@Override
public void show() {
System.out.println("Dog --- show方法");
}
}
class Cat extends Animal{
String name = "猫";
@Override
public void show() {
System.out.println("Cat --- show方法");
}
}
多态的优势
在多态形势下,右边对象可以实现解耦合,便于扩展和维护。
/*
Person p = new Student () ;
p.work( ); //业务逻辑发生改变时,后续代码无需修改
例如:过了几天,不想让学生去工作了,而是想让老师去工作,此时,在代码当中,只需要把创建对象的 new Student();部分修改成new Teacher();
其他地方都不用修改,再调用 work 方法的时候,它实际上运行的是修改之后的 Teacher 类里面的代码。
*/
定义方法的时候,使用父类型作为参数,可以接收所有子类对象,体现多态的扩展性与便利
public class Test {
public static void main(String[] args) {
//调用register方法
register(stu);
register(t);
register(admin);
}
//这个方法既能接收老师、又能接收学生,还能接收管理员
//只能把参数写成这三个类型的父亲
//多态的运用
public static void register(Person p){
p.show();
}
}
多态的弊端
不能调用子类的特有的功能(子类中有 而父类中没有 的函数)
原因:当调用成员方法的时候,编译看左边,运行看右边
javac编译代码的时候,检查父类中没有这个方法,直接报错
引用数据类型的类型转换
自动类型转换
Person p = new Student ( ) ; 把子类对象,赋值给父类类型的变量 由小变大
父类 <—— 子类
强制类型转换
Student s = (Student) p; 把父类类型的变量,强转成子类类型的变量 由大变小
子类 <—— 父类
强制类型转换能解决什么问题?
可以转换成真正的子类类型,从而调用子类独有的功能
转换类型与真实对象类型不一致会报错
转换的时候用 instanceof 关键字进行判断
变量名 instanceof 类名
例如:a instanceof Dog 判断 a 是不是 Dog 类 如果是进行强转 Dog d = (Dog)a; 转换之后变量名为 d 。如果不是,为 false 继续向下判断
if(a instanceof Dog){
Dog d = (Dog)a;
d.lookHome();
}else if(a instanceof Cat){
Cat c = (Cat)a;
c.catchMouse();
}else {
System.out.println("没有这个类型,无法转换");
}
新特性:
先判断 a 是否为 Dog 类型,如果是,则强转成 Dog 类型,转换之后变量名为 d
如果不是,则强转成,结果直接是false
if(a instanceof Dog d){
d.lookHome();
}else if(a instanceof Cat c){
c.catchMouse();
}else {
System.out.println("没有这个类型,无法转换");
}
package Just.a03polymorphismdemo3;
public class Test {
public static void main(String[] args) {
//创建对象 (多态继承)
Animal a = new Dog();
Animal f = new Cat();
//编译看左边,运行看右边
a.eat();
f.eat();
//多态弊端
//不能调用子类的特有的功能
//报错原因?
//当调用成员方法的时候,编译看左边,运行看右边
//那么在编译的时候会先检查左边的父类中没有这个方法,直接报错
//a.lookHome();
//解决方法:
//变回子类类型就可以了
//细节:转换的时候不能瞎转,如果转成其他类型,就会报错。错误例子:Cat c = (Cat) a;因为上面是new Dog();
//变换成子类型 方法一
Dog d = (Dog)a;
d.lookHome();
Cat c = (Cat)f;
c.catchMouse();
//变换成子类型 方法二
//if(a instanceof Dog){
//Dog d = (Dog)a;
//d.lookHome();
//}else if(a instanceof Cat){
//Cat c = (Cat)a;
//c.catchMouse();
//}else {
//System.out.println("没有这个类型,无法转换");
//}
}
}
class Animal{
public void eat(){
System.out.println("动物在吃东西");
}
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃骨头");
}
public void lookHome(){
System.out.println("狗看家");
}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃小鱼干");
}
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}
根据要求完成代码:
1、定义狗类
属性: 年龄,颜色
行为: eat( String something ) (something 表示吃的东西)
看家lookHome方法(无参数)
2、定义猫类
属性: 年龄,颜色
行为: eat( String something ) (something 表示吃的东西)
逮老鼠catchMouse方法(无参数)
3、定义Person类//饲养员
属性: 姓名,年龄
行为: keepPet(Dog dog , String something)
功能:喂养宠物狗,something表示喂养的东西
行为: keepPet(Cat cat , String something)
功能:喂养宠物猫,something表示喂养的东西
生成空参有参构造,set 和 get
4、定义测试类(完成以下打印效果):
keepPet(Dog dog , String something)方法打印的内容如下:
年龄为30岁的老王养了一只黑色的2岁的宠物
2岁的黑颜色的狗两只前腿死死的抱住骨头猛吃
keepPet(Cat cat , String something)方法打印的内容如下:
年龄为25岁的老李养了一只灰颜色的3岁的宠物
3岁的灰颜色的猫眯着眼睛侧着鱼头吃鱼
5、思考:
1、Dog 和 Cat 都是 Animal 的子类,以上案例中针对不同的动物,定义了不同的keepPet方法,过于繁琐,能否简化,并体会简化后的好处?
2、Dog 和 Cat 都是 Animal 的子类,但是都有其特有的方法,能否想办法在keepPet中调用特有方法?
package Just.a04polymorphismdemo4;
public class Animal {
private int age;
private String color;
//无参构造
public Animal() {
}
//有参构造
public Animal(int age, String color) {
this.age = age;
this.color = color;
}
//set 和 get 方法
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
//eat方法
public void eat(String something){
System.out.println("动物在吃" + something);
}
}
==========================================================================
package Just.a04polymorphismdemo4;
public class Dog extends Animal{
//空参构造
public Dog() {
}
//有参构造
public Dog(int age, String color) {
super(age, color);
}
//从写eat方法
@Override
public void eat(String something) {
System.out.println(getAge() + "岁的"+ getColor() + "颜色的狗两只前腿死死的抱住" + something + "猛吃");
}
//lookHome方法
public void lookHome(){
System.out.println("狗在看家");
}
}
==========================================================================
package Just.a04polymorphismdemo4;
public class Cat extends Animal{
//无参构造
public Cat() {
}
//有参构造
public Cat(int age, String color) {
super(age, color);
}
//从写eat方法
@Override
public void eat(String something) {
System.out.println(getAge() + "岁的" + getColor() + "颜色的猫眯着眼睛侧着头吃" + something);
}
//catchMouse方法
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}
==========================================================================
package Just.a04polymorphismdemo4;
public class Person {
private String name;
private int age;
//无参构造
public Person() {
}
//有参构造
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//set 和 get 方法
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 void keepPet(Dog dog ,String something){
System.out.println("年龄为" + age + "岁的" + name + "养了一只" + dog.getColor() + "颜色的" + dog.getAge() + "岁的狗");
dog.eat(something);
}
//饲养猫
public void keepPet(Cat cat ,String something){
System.out.println("年龄为" + age + "岁的" + name + "养了一只" + cat.getColor() + "颜色的" + cat.getAge() + "岁的狗");
cat.eat(something);
}
*/
//想要一个方法,能接收所有的动物,包括猫,包括狗
//方法的形参:可以写这些类的父亲 Animal
//饲养动物
public void keepPet(Animal a ,String something){
if(a instanceof Dog){
Dog d = (Dog)a;
System.out.println("年龄为" + age + "岁的" + name + "养了一只" + a.getColor() + "颜色的" + a.getAge() + "岁的狗");
a.eat(something);
}else if(a instanceof Cat){
Cat c = (Cat)a;
System.out.println("年龄为" + age + "岁的" + name + "养了一只" + a.getColor() + "颜色的" + a.getAge() + "岁的猫");
a.eat(something);
}
}
}
==========================================================================
package Just.a04polymorphismdemo4;
public class Test {
public static void main(String[] args) {
//创建对象并调用方法
Person p1 = new Person("老王",30);
Dog d = new Dog(3,"黑");
p1.keepPet(d,"骨头");
d.lookHome();
System.out.println();
Person p2 = new Person("老李",25);
Cat c = new Cat(2,"灰");
p2.keepPet(c,"鱼");
c.catchMouse();
}
}
==========================================================================
年龄为30岁的老王养了一只黑颜色的3岁的狗
3岁的黑颜色的狗两只前腿死死的抱住骨头猛吃
狗在看家
年龄为25岁的老李养了一只灰颜色的2岁的猫
2岁的灰颜色的猫眯着眼睛侧着头吃鱼
猫抓老鼠
什么是包?
包就是文件夹。用来管理各种不同功能的 Java 类,方便后期代码维护。
**包名的规则:**公司域名反写 + 包的作用,需要全部英文小写,见名知意。
什么是全类名?
包名 + 类名
使用其他类的规则:
package Just.test;
import Just.domain.Teacher;
public class Test {
public static void main(String[] args) {
//创建对象
//1、使用同一个包中的类时,不需要导包
Student stu = new Student();
stu.setName("王勇");
stu.setAge(21);
System.out.println(stu.getName() + "、" + stu.getAge());
//2、使用 java.lang 包中的类时,不需要导包
String s = "韩炜";
System.out.println(s);
//3、其他情况都需要导包
Teacher t = new Teacher();
//4、如果同时使用两个包中的同名类时,需要用全类名
Just.Dog1.Dog d1 = new Just.Dog1.Dog();
Just.Dog2.Dog d2 = new Just.Dog2.Dog();
}
}
最终的 ——> 不可被改变的
final修饰的成分 | 解释 | 使用场景 | final使用举例 |
---|---|---|---|
方法 | 表明该方法是最终方法,不能被重写 | 定义一些规则,不希望被修改 | public final void show() |
类 | 表明该类是最终类,不能被继承 | final class Fu | |
变量 | 叫做 常量,只能被赋值一次 | 定义一个变量,不想再让他进行改变了 | final int num = 21; final Student s tu = new Student(“鑫鑫”,21) |
常量
实际开发中,常量一般作为系统的配置信息,方便维护,提高可读性
常量的命名规范:
细节:
final 修饰的变量是基本数据类型:那么变量存储的数据值不能发生改变。
final 修饰的变量是引用数据类型:那么变量存储的地址值不能发生改变,对象内部的可以改变。
核心:常量记录的数据是不能发生改变的。
知识回顾:字符串是不能改变的
原因:字符串的底层是被 private 和 final 修饰的
package Just.test1;
public class Test {
public static void main(String[] args) {
/*
final 修饰的变量是**基本数据类型**:那么变量存储的==数据值==不能发生改变。
final 修饰的变量是**引用数据类型**:那么变量存储的==地址值==不能发生改变,**对象内部的可以改变**。
*/
final double PI = 3.14;
//创建对象
final Student STU = new Student("鑫鑫",21);
System.out.println(STU.getName() + "、" + STU.getAge());
STU.setName("肉墩");
STU.setAge(20);
System.out.println(STU.getName() + "、" + STU.getAge());
//数组
final int[] ARR = {1,2,3,4,5};
//遍历数组
for (int i = 0; i < ARR.length; i++) {
System.out.print(ARR[i] + "、");
}
ARR[0] = 90;
ARR[1] = 98;
//遍历数组
for (int i = 0; i < ARR.length; i++) {
System.out.print(ARR[i] + "、");
}
}
}
===========================================================================================
运行结果:
鑫鑫、21
肉墩、20
1、2、3、4、5、90、98、3、4、5、
Process finished with exit code 0
权限修饰符的分类:
有四种 , 作用范围由小到大:private < 空着不写(缺省/默认)< protected < public
修饰符(作用范围) | 同一个类中 | 同一个包中其他类 | 不同包下的子类 | 不同包下的无关类 |
---|---|---|---|---|
private | √ | |||
空着不写 | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
权限修饰符的使用规则
实际开发中,一般只用 private 和 public
特例:如果方法中的代码是抽取其他方法中共性代码,这个方法一般也私有。
代码块种类 | 位置 | 解释 |
---|---|---|
局部代码块 | 方法里面 | 写在方法里面的一对大括号 |
构造代码块 | 方法外,类里面 | |
静态代码块 | static 修饰的静态代码块 | static + 构造代码块 |
局部代码块:
构造代码块:
public class Student {
private String name;
private int age;
//构造代码块
{
System.out.println("开始创建对象了");
}
//无参构造
public Student() {
System.out.println("空参构造");
}
public Student(String name, int age) {
System.out.println("有参构造");
this.name = name;
this.age = age;
}
静态代码块
格式:static{}
特点:需要通过static 关键字修饰,随着类的加载而加载,并且自动触发、只执行一次
使用场景:在类加载的时候,做一些数据初始化的时候使用。
public class Student {
private String name;
private int age;
//静态代码块
static {
System.out.println("静态代码块执行了");
}
public Student() {
System.out.println("空参构造");
}
public Student(String name, int age) {
System.out.println("有参构造");
this.name = name;
this.age = age;
}
}
========================================================
public class Test {
//静态代码块
static {
System.out.println("测试静态代码块");
}
public static void main(String[] args) {
//创建对象
Student s1 = new Student();
Student s2 = new Student("鑫鑫",21);
}
}
========================================================
运行结果:
测试静态代码块
静态代码块执行了
空参构造
有参构造
**抽象方法:**将共性的行为(方法)抽取到父类之后。
由于每一个子类执行的内容是不一样的,
所以,在父类中不能确定具体的方法体。
该方法就可以定义为抽象方法。
**抽象类:**如果一个类中存在抽象方法,那么该类就必须声明为抽象类
抽象方法定义格式:
public abstract 返回值类型 方法名( 参数列表 );
注意:定义抽象方法,省略 {}
抽象类的定义格式:
public abstract class 类名 {}
子类继承抽象类之后,如何重写抽象方法
抽象类不能实例化(即不能创建对象)
抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
可以有构造方法
抽象类中构造方法的作用:当创建子类对象的时,给属性进行赋值
抽象类的子类
要么重写抽象类中的所有方法
要么是抽象类
练习:编写带有抽象类的标准 Javabean 类
青蛙frog 属性:名字,年龄 行为:吃虫子,喝水
狗Dog 属性:名字,年龄 行为:吃骨头,喝水
山羊Sheep 属性
package Just.a02abstractdemo2;
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 void drink(){
System.out.println(getName() + "在喝水");
}
public abstract void eat();
}
===============================================================================
package Just.a02abstractdemo2;
public class Frog extends Animal{
public Frog() {
}
public Frog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println(getName() + "在吃虫子");
}
}
===============================================================================
package Just.a02abstractdemo2;
public class Dog extends Animal{
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println(getName() + "在吃骨头");
}
}
===============================================================================
package Just.a02abstractdemo2;
public class Sheep extends Animal{
public Sheep() {
}
public Sheep(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println(getName() + "在吃草");
}
}
===============================================================================
package Just.a02abstractdemo2;
public class Test {
public static void main(String[] args) {
//创建对象
Frog f = new Frog("青蛙小绿",2);
System.out.println(f.getName() + "、" + f.getAge());
f.drink();
f.eat();
System.out.println();
Dog d = new Dog("狗",5);
System.out.println(d.getName() + "、" + d.getAge());
d.drink();
d.eat();
System.out.println();
Sheep s = new Sheep("山羊",7);
System.out.println(s.getName() + "、" + s.getAge());
s.drink();
s.eat();
System.out.println();
}
}
===============================================================================
青蛙小绿、2
青蛙小绿在喝水
青蛙小绿在吃虫子
狗、5
狗在喝水
狗在吃骨头
山羊、7
山羊在喝水
山羊在吃草
接口就是一种规则,是对行为的抽象。
接口用关键字 interface 来定义
public interface 接口名 { }
接口不能实例化(即接口不能创建对象)
接口和类之间是实现关系,通过 implements 关键字表示
public class 类名 implements 接口名 { }
接口的子类(实现类)
要么重写接口中的所有抽象方法
要么是抽象类
注意:
接口和类的实现关系,可以单实现,也可以多实现。
public class 类名 implements 接口名1 , 接口名2 { }
实现类还可以在继承一个类的同时实现多个接口。
public class 类名 extends 父类 implements 接口名1 , 接口名2 { }
练习:带有接口和抽象类的标准 Javabean类
青蛙frog 属性:名字,年龄 行为:吃虫子,蛙泳
狗Dog 属性:名字,年龄 行为:吃骨头,狗刨
兔子 属性:名字,年龄 行为:吃胡萝卜
package Just.a01interfacedemo1;
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 Just.a01interfacedemo1;
public interface Swim {
public abstract void swim();
}
========================================================================
package Just.a01interfacedemo1;
public class Frog extends Animal implements Swim{
public Frog() {
}
public Frog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println(getName() + "吃虫子");
}
@Override
public void swim() {
System.out.println("游泳方式:蛙泳");
}
}
========================================================================
package Just.a01interfacedemo1;
public class Dog extends Animal implements Swim{
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println(getName() + "吃骨头");
}
@Override
public void swim() {
System.out.println("游泳方式:狗刨");
}
}
========================================================================
package Just.a01interfacedemo1;
public class Rabbit extends Animal{
public Rabbit() {
}
public Rabbit(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println(getName() + "吃胡萝卜");
}
}
========================================================================
package Just.a01interfacedemo1;
public class Test {
public static void main(String[] args) {
//创建对象
Frog f = new Frog("小绿",1);
System.out.println(f.getName() + "、" + f.getAge() + "岁");
f.eat();
f.swim();
Dog d = new Dog("阿黄",5);
System.out.println(d.getName() + "、" + d.getAge() + "岁");
d.eat();
d.swim();
Rabbit r = new Rabbit("大白",3);
System.out.println(r.getName() + "、" + r.getAge() + "岁");
r.eat();
}
}
========================================================================
小绿、1岁
小绿吃虫子
游泳方式:蛙泳
阿黄、5岁
阿黄吃骨头
游泳方式:狗刨
大白、3岁
大白吃胡萝卜
成员变量
只能是常量
默认修饰符:public static final 在接口中定义变量的时候,可以不用写
接口名可以调用接口中的成员变量
构造方法
没有
成员方法
只能是抽象方法
默认修饰符:public abstract 在接口中定义方法的时候,可以不用写
**JDK7 以前:**接口中只能定义抽象方法。
JDK8 的新特性:接口中可以定义有方法体的方法。
JDK9 的新特性:接口中可以定义私有方法。
类和类的关系
继承关系,只能单继承,不能多继承,但是可以多层继承
类和接口的关系
实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
当接口中有重复的方法时,类中只重写一遍
package Just.a02interfacedemo2;
public interface Inter1 {
public abstract void method1();
public abstract void method2();
public abstract void method3();
}
========================================================================
package Just.a02interfacedemo2;
public interface Inter2 {
public abstract void method2();
public abstract void method3();
public abstract void method4();
}
========================================================================
package Just.a02interfacedemo2;
public class InterImpl implements Inter1,Inter2{
@Override
public void method1() {
}
@Override
public void method2() {
}
@Override
public void method3() {
}
@Override
public void method4() {
}
}
接口和接口的关系
继承关系,可以单继承,也可以多继承
细节:如果实现类实现了最下面的子接口,那么就需要重写所有的抽象方法
package Just.a03interfacedemo3;
public interface Inter1 {
public abstract void method1();
}
========================================================================
package Just.a03interfacedemo3;
public interface Inter2 {
public abstract void method2();
}
========================================================================
package Just.a03interfacedemo3;
public interface Inter3 extends Inter1,Inter2{
public abstract void method3();
}
========================================================================
package Just.a03interfacedemo3;
public class InterImpl implements Inter3{
@Override
public void method1() {
}
@Override
public void method2() {
}
@Override
public void method3() {
}
}
上面的例子中,Inter3 继承了 Inter1 和 Inter2 ,所以当类InterImpl 使用接口Inter3 时,重写了Inter3 中的抽象方法,还重写了Inter3 重 Inter1 和 Inter2 中继承的方法。
练习:编写带有接口和抽象类的标准 Javabean 类
我们现有乒乓球运动员和篮球运动员,乒乓球教练和篮球教练。
为了出国交流,跟乒乓球相关人员都需要学习英语。
请用所有知识分析,在这个案例中,哪些是具体类,哪些是抽象类,哪些是接口?
乒乓球运动员:姓名,年龄,学打乒乓球,说英语
乒乓球教练:姓名,年龄,教打乒乓球,说英语
篮球运动员:姓名,年龄,学打篮球
篮球教练:姓名,年龄,教打篮球
package Just.a04interfacedemo4;
public abstract 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 Just.a04interfacedemo4;
public abstract class Athlete extends Person{
public Athlete() {
}
public Athlete(String name, int age) {
super(name, age);
}
public abstract void study();
}
========================================================================
package Just.a04interfacedemo4;
public abstract class Coach extends Person{
public Coach() {
}
public Coach(String name, int age) {
super(name, age);
}
public abstract void teach();
}
========================================================================
package Just.a04interfacedemo4;
public interface Speak {
public abstract void speak();
}
========================================================================
package Just.a04interfacedemo4;
public class TableTennisPlayer extends Athlete implements Speak{
public TableTennisPlayer() {
}
public TableTennisPlayer(String name, int age) {
super(name, age);
}
@Override
public void study() {
System.out.println("乒乓球运动员在学习打乒乓球");
}
@Override
public void speak() {
System.out.println("乒乓球运动员在说英语");
}
}
========================================================================
package Just.a04interfacedemo4;
public class BasketballPlayer extends Athlete{
public BasketballPlayer() {
}
public BasketballPlayer(String name, int age) {
super(name, age);
}
@Override
public void study() {
System.out.println("篮球运动员在学习学打篮球");
}
}
========================================================================
package Just.a04interfacedemo4;
public class TableTennisCoach extends Coach implements Speak{
public TableTennisCoach() {
}
public TableTennisCoach(String name, int age) {
super(name, age);
}
@Override
public void teach() {
System.out.println("乒乓球教练在教如何打乒乓球");
}
@Override
public void speak() {
System.out.println("乒乓球教练在说英语");
}
}
========================================================================
package Just.a04interfacedemo4;
public class BasketballCoach extends Coach{
public BasketballCoach() {
}
public BasketballCoach(String name, int age) {
super(name, age);
}
@Override
public void teach() {
System.out.println("篮球教练在教如何打篮球");
}
}
========================================================================
鑫鑫、21
乒乓球运动员在学习打乒乓球
乒乓球运动员在说英语
肉墩、35
篮球教练在教如何打篮球
1、JDK7以前:接口中只能定义抽象方法。
2、JDK8的新特性:接口中可以定义有方法体的方法。(默认方法、静态方法)。
默认方法
允许在接口中定义默认方法,需要使用关键字 default 修饰
作用:解决接口升级的问题
接口中默认方法的定义格式:
接口中默认方法的注意事项:
public interface InterA {
public abstract void method();
public default void show(){
System.out.println("InterA接口中的默认方法 --- show");
}
}
========================================================================
public interface InterB {
public default void show(){
System.out.println("InterB接口中的默认方法 --- show");
}
}
========================================================================
public class InterImpl implements InterA,InterB {
@Override
public void method() {
System.out.println("实现类重写的抽象方法");
}
//由于接口 InterA和 InterB 中存在相同名字的默认方法,子类(实现类)就必须对该方法进行重写
@Override
public void show() {
System.out.println("重写接口中的默认方法");
}
}
========================================================================
public class Test {
public static void main(String[] args) {
//创建对象
InterImpl ii = new InterImpl();
//调用重写的method方法
ii.method();
//调用默认方法show
ii.show();
}
}
========================================================================
运行结果:
实现类重写的抽象方法
重写接口中的默认方法
静态方法
接口中静态方法的定义格式:
接口中静态方法的注意事项:
静态方法不能被重写
静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
public 可以省略,static 不能省略
public interface Inter {
public abstract void method();
public static void show(){
System.out.println("Inter 接口中的静态方法");
}
}
========================================================================
public class InterImpl implements Inter{
@Override
public void method() {
System.out.println("InterImpl 重写的抽象方法");
}
//不叫重写,只是InterImpl 中的方法与 接口 Inter里面的方法重名
public static void show(){
System.out.println("InterImpl 类中的静态方法");
}
}
========================================================================
public class Test {
public static void main(String[] args) {
//调用接口中的静态方法
Inter.show();
//调用实现类中的静态方法
InterImpl.show();
InterImpl ii = new InterImpl();
ii.method();
}
}
========================================================================
运行结果:
Inter 接口中的静态方法
InterImpl 类中的静态方法
InterImpl 重写的抽象方法
3、JDK9的新特性:接口中可以定义私有方法。
接口中私有方法的定义格式:
为默认方法服务:
为静态方法服务
public interface InterA {
public default void show1(){
System.out.println("show1 默认方法开始执行了");
show3();
}
public default void show2(){
System.out.println("show1 默认方法开始执行了");
show3();
}
//普通的私有方法,给默认方法服务的
private void show3(){
System.out.println("记录程序在运行过程的各种细节,这里有100行代码");
}
}
========================================================================
public interface InterB {
public static void show1(){
System.out.println("show1 静态方法开始执行了");
show3();
}
public static void show2(){
System.out.println("show1 静态方法开始执行了");
show3();
}
//静态的私有方法,给静态的方法服务的
private static void show3(){
System.out.println("记录程序在运行过程的各种细节,这里有100行代码");
}
}
========================================================================
public class InterImpl implements InterA,InterB{
}
========================================================================
public class Test {
public static void main(String[] args) {
//创建对象
InterImpl ii = new InterImpl();
//调用默认方法
ii.show1();
ii.show2();
System.out.println();
//调用静态方法
InterB.show1();
InterB.show2();
}
}
========================================================================
运行结果:
show1 默认方法开始执行了
记录程序在运行过程的各种细节,这里有100行代码
show2 默认方法开始执行了
记录程序在运行过程的各种细节,这里有100行代码
show1 静态方法开始执行了
记录程序在运行过程的各种细节,这里有100行代码
show2 静态方法开始执行了
记录程序在运行过程的各种细节,这里有100行代码
1、接口代表规则,是行为的抽象。想要让哪个类拥有一个行为,就让这个类实现对应的接口就可以了。
2、当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方式称之为接口多态。
设计模式( Design pattern ) 是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验总结。
使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。
简单理解:设计模式就是各种套路。
适配器设计模式: 解决接口与接口实现类之间的矛盾问题。
总结:
当一个接口中抽象方法过多,但是我只要使用其中一部分的时候,就可以采用适配器设计模式
书写步骤:
**注意:**如果真正实现类还继承其他类,由于类不能多继承,所以用下面解决方案:
让中间类继承真正实现类本要继承的类,再让真正实现类,继承中间类,通过间接继承,让真正实现类继承其本要继承的类
public interface Inter {
public abstract void method1();
public abstract void method2();
public abstract void method3();
public abstract void method4();
public abstract void method5();
public abstract void method6();
public abstract void method7();
public abstract void method8();
public abstract void method9();
public abstract void method10();
}
========================================================================
public abstract class InterAdapter implements Inter{
//所有重写方法进行空实现
@Override
public void method1() {
}
@Override
public void method2() {
}
...............
}
========================================================================
public class InterImpl extends InterAdapter{
//需要用到哪个方法,就重写哪个方法
@Override
public void method5() {
System.out.println("只要用第五个方法");
}
}
1、什么是内部类?
举例:在 A 类的内部定义 B 类,B 类就被称为内部类
2、什么时候用到内部类?
B 类表示的事物是 A 类的一部分,且 B 单独存在没有意义。
比如:汽车的发动机,ArrayList 的迭代器,人的心脏等等
3、内类的详情
内部类表示的事物是外部类的一部分
内部类单独出现没有任何意义
4、内部类的访问特点:
练习:
需求:写一个 Javabean 类描述汽车。
属性:汽车的品牌,车龄,颜色,发动机的品牌,使用年限。
public class Car {
String carName;
int carAge;
String carColor;
public void show(){
System.out.println(carName);
//System.out.println(engineName);
//外部类要访问内部类的成员,必须创建对象
Engine e = new Engine();
System.out.println(e.engineName);
}
class Engine{
String engineName;
int engineAge;
public void show(){
System.out.println(engineName);
//内部类可以直接访问外部类的成员,包括私有
System.out.println(carName);
}
}
}
写在成员位置的,属于外部类的成员( 类内,方法外)
成员内部类可以被一些修饰符所修饰,比如:private 、默认、protected、public、static 等
在成员内部类里面,JDK16 之前不能定义静态变量,JDK16 开始才可以定义静态变量。
public class Car { 外部类
String carName ;
int carAge ;
int carColor ;
class Engine { 成员内部类
String engineName ;
int engineAge ;
}
}
方式一:
在外部类中编写方法,对外提供内部类的对象。
使用场景:当用 private 权限修饰符修饰内部类的时候
public class Outer {
//内部类
private class Inner{
}
//格式一:外部类编写方法,对外提供内部类对象
public Inner getInstance(){
return new Inner();
}
}
调用方法:
//外部类的对象
Outer o = new Outer();
方法一:用变量接收外部类的方法
Object inner = o.getInstance();
System.out.println(inner);
方法二:
System.out.println(o.getInstance());
方式二:
直接创建格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
范例:Outer.Inner oi = new Outer().new Inter() ;
使用场景:非使用 private 权限修饰符
外部类成员变量和内部类成员变量重名时,在内部类如何访问?
System.out.println(Outer.this.变量名)
package Just.ao3innerclassdemo3;
public class Outer {
private int a = 10;
class Inner{
private int a = 20;
public void show(){
int a = 30;
System.out.println(a); //30
System.out.println(this.a); //20
//Outer.this 获取了外部类对象的地址值
System.out.println(Outer.this.a); //10
}
}
}
========================================================================
package Just.ao3innerclassdemo3;
public class Test {
public static void main(String[] args) {
//创建内部类对象对象,并调用show方法
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
========================================================================
运行结果:
30
20
10
静态内部类也是成员内部类的一种
静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建对象
public class Car { 外部类
String carName ;
int carAge ;
int carColor ;
static class Engine { 成员内部类
String engineName ;
int engineAge ;
}
}
==创建静态内部类对象的格式:==外部类名.内部类名 对象名 = new 外部类名.内部类名( ) ;
范例:Outer.Inter oi = new Outer.Inter();
==调用非静态方法的格式:==先创建对象,用对象调用
范例:Outer.Inter oi = new Outer.Inter();
oi.show1();
==调用静态方法的格式:==外部类名.内部类名.方法名();
范例:Outer.Inter.show2();
package Just.ao4innerclassdemo4;
public class Outer {
int a = 10;
static int b = 20;
//静态内部类
static class Inter{
//非静态方法
public void show1(){
System.out.println("非静态的方法被调用了");
//静态内部类访问外部类中的非静态变量和静态方法,需要创建对象
Outer o = new Outer();
System.out.println(o.a);
//静态内部类直接访问外部类中的静态变量和静态方法
System.out.println(b);
}
//静态方法
public static void show2(){
System.out.println("静态的方法被调用了");
//静态内部类访问外部类中的非静态变量和静态方法,需要创建对象
Outer o = new Outer();
System.out.println(o.a);
//静态内部类直接访问外部类中的静态变量和静态方法
System.out.println(b);
}
}
}
========================================================================
package Just.ao4innerclassdemo4;
public class Test {
public static void main(String[] args) {
//创建静态内部类的对象
//只要是静态的东西,都可以用类名.直接获取
Outer.Inter oi = new Outer.Inter();
//调用非静态方法
oi.show1();
//调用静态方法
Outer.Inter.show2();
}
}
========================================================================
运行结果:
非静态的方法被调用了
10
20
静态的方法被调用了
10
20
1、将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量。
2、外界无法直接使用,需要在方法内部创建对象并使用。
3、该类可以直接访问外部类的成员,也可以访问方法内的局部变量。
package Just.ao5innerclassdemo5;
public class Outer {
//外部类的成员
int b = 20;
public void show(){
//方法内的局部变量
int a = 10;
//局部内部类
class Inner{
String name;
int age;
public void method1(){
//内部类可以直接访问外部类的成员,也可以访问方法内的局部变量
System.out.println(a);
System.out.println(b);
System.out.println("局部内部类中的methodl方法");
}
public static void method2(){
System.out.println();
}
}
//外界是无法直接使用局部内部类,需要在方法内部创建对象并使用
//创建局部内部类的对象
Inner i = new Inner();
System.out.println(i.name);
System.out.println(i.age);
i.method1();
Inner.method2();
}
}
========================================================================
package Just.ao5innerclassdemo5;
public class Test {
public static void main(String[] args) {
//调用show方法,让代码执行
Outer o = new Outer();
o.show();
}
}
匿名内部类:隐藏了名字的内部类,可以写在成员位置、局部位置
格式:
new (父)类名或者接口名 () { 继承 \ 实现
重写方法; 方法重写
}; 创建对象
格式细节:
包含了继承或实现,方法重写,创建对象。
整体就是一个类的子类对象或者接口的实现类对象
解释:new (父)类名 或者 接口名();是 new 出来的 没有名字的类的对象
**真正没有名字的类是 { } **
{ } 与 前面的对象,要么是继承关系,要么是实现关系
在 { } 里面重写抽象方法
总结:匿名内部类是集:{ } 匿名类 ——> 继承 或 接口 ——> 方法重写 ——> 创建匿名类对象 于一体的存在
整体,呈现出来的是 匿名类的对象
使用场景:
当方法的参数是接口时或者类时,
以接口为例,可以传递这个接口的实现类对象,
如果实现类只要使用一次,就可以用匿名内部类简化代码。
举例:
package Just.ao6innerclassdemo6;
public interface Swim {
public abstract void swim();
}
========================================================================
package Just.ao6innerclassdemo6;
public abstract class Animal {
public abstract void eat();
}
========================================================================
package Just.ao6innerclassdemo6;
public class Test {
public static void main(String[] args) {
//编写匿名内部类的代码
new Swim(){
@Override
public void swim() {
System.out.println("重写了游泳的方法");
}
};
/*
new Animal(){
@Override
public void eat() {
System.out.println("重写了eat方法");
}
};
上面注释的代码表示:创建了 Animal 子类的对象,其中包括,匿名类继承父类——> 匿名类重写父类的抽方法——> 创建匿名类的对象
*/
//在测试类中调用下面的 method 方法?
method(
//把 Animal 子类(匿名类)的对象,作为参数,调用的 method 方法
new Animal() {
@Override
public void eat() {
System.out.println("狗吃骨头");
}
}
);
}
public static void method(Animal a){//Animal a = 子类对象;符合:标准多态
a.eat();//编译看左边,运行看右边
}
}
========================================================================
运行结果:
狗吃骨头
补充:匿名内部类的其他使用
package Just.ao6innerclassdemo6;
public class Test2 {
public static void main(String[] args) {
/*下面的整体,可以理解为 Swim接口的 实现类对象
我们可以把此对象,赋值给一个 Swim接口的类型的 变量 ————> 进而实现 接口的多态
*/
Swim s = new Swim(){
@Override
public void swim() {
System.out.println("重写游泳后的方法1");
}
};
//用对象 s 调用实现类的重写方法
//编译看左边,运行看右边
s.swim();
/*下面的整体,可以理解为 Swim接口的 实现类对象
既然是实现类的对象,那可以调用类的方法
首先调用实现类中的方法
*/
new Swim(){
@Override
public void swim() {
System.out.println("重写游泳后的方法2");
}
}.swim();
}
}
========================================================================
运行结果:
重写游泳后的方法1
重写游泳后的方法2