本学习笔记的图片和题目均来源于黑马程序员,本人小白一枚,如有错误请及时指出,感谢感谢
由于本文时间跨度有点长,代码过多,本文不一一列出代码
一.static
(1)static表示静态,是Java中的一个修饰符,可以修饰成员方法,成员变量。
(2)被static修饰的成员变量,叫做静态变量
被static修饰的成员方法,叫做静态方法
(3)静态变量的特点:被该类所有对象共享
不属于对象,属于类。
随着类的加载而加载,优先于对象存在
调用方式:
类名调用(推荐)
对象名调用
(4)静态方法的特点:多用在测试类和工具类中
Javabean类中很少会用
调用方式:
类名调用(推荐)
对象名调用
(5)static内存图
(6)工具类:帮助我们做一些事情的,但是不描述任何事物的类
Javabean类:用来描述一类事物的类。比如,Student,Teacher,Dog,Cat等
测试类:用来检查其他类是否书写正确,带有main方法的类,是程序的入口。
(7)工具类特点:类名见名知意
私有化构造方法
方法定义为静态
练习一
public class ArrayUtil {
private ArrayUtil() {
}
public static String printArr(int[] arr) {
StringBuilder sb = new StringBuilder();
sb.append("[");
for(int i = 0; i < arr.length; ++i) {
if (i == arr.length - 1) {
sb.append(arr[i]);
} else {
sb.append(arr[i] + ",");
}
}
sb.append("]");
return sb.toString();
}
public static double getAverage(double[] arr) {
double sum = (double)0.0F;
for(int i = 0; i < arr.length; ++i) {
sum += arr[i];
}
double avg = sum / (double)arr.length;
return avg;
}
}
public class TestDemo {
public TestDemo() {
}
public static void main(String[] args) {
int[] arr = new int[]{10, 20, 50, 34, 100};
double[] arr1 = new double[]{(double)10.0F, (double)20.0F, (double)50.0F, (double)34.0F, (double)100.0F};
String str = ArrayUtil.printArr(arr);
double s = ArrayUtil.getAverage(arr1);
System.out.println(str);
System.out.println(s);
}
}
练习二
import java.util.ArrayList;
public class StudentUtil {
private StudentUtil() {
}
public static int Max(ArrayList<Student> list) {
int max = ((Student)list.get(0)).getAge();
for(int i = 1; i < list.size(); ++i) {
int tempAge = ((Student)list.get(i)).getAge();
if (max < tempAge) {
max = tempAge;
}
}
return max;
}
}
public class Student {
private String name;
private int age;
private String gender;
Student() {
}
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return this.gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
import java.util.ArrayList;
import java.util.Scanner;
public class StudentTest {
public StudentTest() {
}
public static void main(String[] args) {
ArrayList<Student> list = new ArrayList();
Scanner sc = new Scanner(System.in);
for(int i = 0; i < 3; ++i) {
String name = sc.next();
int age = sc.nextInt();
String gender = sc.next();
Student stu = new Student(name, age, gender);
list.add(stu);
}
int m = StudentUtil.Max(list);
System.out.println(m);
}
}
(8)static的注意事项
静态方法只能访问静态变量和静态方法。
非静态方法可以访问静态变量或者静态方法,也可以访问非静态的成员变量和非静态的成员方法。
静态方法中是没有this关键字。
1.代码方面理解
2.内存方面理解
(9)重新认识main方法
public class HelloWorld {
public static void main(String[] args) {
System.out.println("HelloWorld");}}
public:被JVM调用,访问权限足够大
static:被JVM调用,不用创建对象,直接类名访问,因为main方法是静态的,所以测试类中其他方法也需要是静态的。
void:被JVM调用,不需要给JVM返回值
main:一个通用的名称,虽然不是关键字,但是可以被JVM识别
String[] args:以前用于接收键盘录入数据的,现在没用。[]数组,String数据类型,args数组名。
空格分隔,代表有三个参数,传给args,如果没有空格,就是一个参数
二.继承
(1)面向对象三大特征:
1.封装:对象代表什么,就得封装对应的数据,并提供数据对应的行为。
2.继承:让类和类之间建立起父子关系
3.多态。
(2)继承概述:Java中提供一个关键字extends,用这个关键字,我们可以让一个类和另一个类建立起继承关系。
格式:public class Student extends Person {}
Student称为子类(派生类),Person称为父类(基类或超类)。
(3)使用继承的好处
可以把多个子类中重复的代码抽取到父类中,子类可以直接使用,减少代码冗余,提高代码的复用性。
(4)什么时候使用继承
当类与类之间,存在相同共性的内容,并满足子类是父类中的一种,就可以考虑使用继承,来优化代码
(5)继承后子类的特点
子类可以得到父类的属性和行为,子类可以使用。
子类可以在父类的基础上新增其他功能,子类更强大。
(6)继承的特点
1. Java只能单继承:一个类只能继承一个直接父类。
单继承:一个子类只能继承一个父类
2:Java不支持多继承、但是支持多层继承。
不支持多继承:子类不能同时继承多个父类
多层继承:子类 A 继承父类日,父类B 可以继承父类 C
3.Java中所有的类都直接或者间接继承于Object类。
4.子类只能访问父类中非私有的成员
练习1:(自己设计一个继承体系)
现在有四种动物:布偶猫、中国狸花猫、哈士奇、泰迪。
暂时不考虑属性,只要考虑行为。
请按照继承的思想特点进行继承体系的设计。
四种动物分别有以下的行为:
布偶猫:吃饭、喝水、抓老鼠
中国狸花猫:吃饭、喝水、抓老鼠
哈士奇:吃饭、喝水、看家、拆家
泰迪:吃饭、喝水、看家、蹭一蹭
使用画图法分析继承体系
画图:从下往上画
下面:子类
上面:父类
写代码:从上往下写。
需要把子类中的共性内容抽取到父类中
核心:1.共性内容抽取
2.子类是父类中的一种
注意: 子类只能访问父类中非私有的成员
private:只能在本类中访问,子类无法访问。
public class Animal {
public Animal() {
}
public void eat() {
System.out.println("吃饭");
}
public void drink() {
System.out.println("喝水");
}
}
public class Cat extends Animal {
public Cat() {
}
public void catchMouse() {
System.out.println("捉老鼠");
}
}
public class Dog extends Animal {
public Dog() {
}
public void lookHome() {
System.out.println("看家");
}
}
public class Husky extends Dog {
public Husky() {
}
public void breakHome() {
System.out.println("拆家");
}
}
public class LiHua extends Cat {
public LiHua() {
}
}
public class Ragdoll extends Cat {
public Ragdoll() {
}
}
public class Teddy extends Dog {
public Teddy() {
}
public void Touch() {
System.out.println("蹭一蹭");
}
}
public class Test {
public Test() {
}
public static void main(String[] args) {
Ragdoll ragdoll = new Ragdoll();
LiHua lihua = new LiHua();
Husky husky = new Husky();
Teddy teddy = new Teddy();
ragdoll.drink();
ragdoll.eat();
ragdoll.catchMouse();
lihua.drink();
lihua.eat();
lihua.catchMouse();
husky.eat();
husky.drink();
husky.lookHome();
husky.breakHome();
teddy.drink();
teddy.eat();
teddy.lookHome();
teddy.Touch();
}
}
(7)子类到底能继承父类中的哪些内容
1.父类的构造方法不能被子类继承:如果能的话,父类的构造方法在子类中会和构造方法的特点冲突,所以不能被子类继承。
如果一个类中没有构造方法,虚拟机会自动添加一个默认的
2.成员变量可以被继承
非私有,私有成员变量都可以被继承
非私成员变量可以直接被调用,私有成员变量要通过set和get方法被调用。
继承的内存图
非私有
私有
4.私有成员方法不能被继承,非私有成员方法可以被继承
虚方法表:父类生成虚方法表,表中可以存储非static,非private,非final修饰的成员方法,只有父类中的虚方法才能被子类继承,父类将虚方法表继承给子类,表中有非私有成员方法,没有私有成员方法,所以,非私有成员方法可以被继承,私有成员方法无法被继承。
内存图
使用内存分析工具分析
(8)继承中:成员变量的访问特点
1.继承中成员变量直接访问特点:就近原则
就近原则:谁离我近,我就用谁。
先在局部位置找,本类成员位置找,父类成员位置找,逐级往上。
2.如果出现了重名的成员变量怎么办?
this调用:就近原则。
super调用:直接找父类。
class Fu {
Fu() {
}
public void eat() {
System.out.println("吃米饭");
}
public void drink() {
System.out.println("喝开水");
}
}
class Zi1 extends Fu {
Zi1() {
}
public void Show() {
this.eat();
this.drink();
super.eat();
super.drink();
}
}
class Zi2 extends Fu {
Zi2() {
}
public void eat() {
System.out.println("吃意大利面");
}
public void drink() {
System.out.println("喝凉水");
}
public void Show() {
this.eat();
this.drink();
super.eat();
super.drink();
}
}
public class Test {
public Test() {
}
public static void main(String[] args) {
Zi1 z1 = new Zi1();
Zi2 z2 = new Zi2();
z1.Show();
z2.Show();
}
}
(9)方法重写
1.方法的重写
当父类的方法不能满足子类现在的需求时,需要进行方法重写
2.书写格式
在继承体系中,子类出现了和父类中一模一样的方法声明,我们就称子类这个方法是重写的方法。
3.@Override重写注解
①.@Override是放在重写后的方法前,校验子类重写时语法是否正确。
②.加上注解后如果有红色波浪线,表示语法错误。
③.建议重写方法都加@Override注解,代码安全,优雅!
4.方法重写的本质:覆盖虚方法表中的方法
5.方法重写注意事项和要求
①.重写方法的名称、形参列表必须与父类中的一致。
②.子类重写父类方法时,访问权限子类必须大于等于父类(暂时了解:空着不写<protected < public)
③.子类重写父类方法时,返回值类型子类必须小于等于父类
④.建议:重写的方法尽量和父类保持一致。
⑤.只有被添加到虚方法表中的方法才能被重写
练习一
画图
public class Dog {
public Dog() {
}
public void eat() {
System.out.println("吃狗粮");
}
public void drink() {
System.out.println("喝水");
}
public void lookHome() {
System.out.println("看家");
}
}
public class Husky extends Dog {
public Husky() {
}
public void breakHome() {
System.out.println("拆家");
}
public void Show() {
this.eat();
this.drink();
this.lookHome();
this.breakHome();
}
}
public class sharPei extends Dog {
public sharPei() {
}
public void eat() {
super.eat();
System.out.println("吃骨头");
}
public void Show() {
this.eat();
this.drink();
this.lookHome();
}
}
public class tianYuan extends Dog {
public tianYuan() {
}
public void eat() {
System.out.println("吃剩饭");
}
public void Show() {
this.eat();
this.drink();
this.lookHome();
}
}
public class Test {
public Test() {
}
public static void main(String[] args) {
Husky h = new Husky();
sharPei s = new sharPei();
tianYuan t = new tianYuan();
h.Show();
s.Show();
t.Show();
}
}
(10)继承中:构造方法的访问特点
父类中的构造方法不会被子类继承,但是可以通过super调用。
子类中所有的构造方法默认先访问父类中的无参构造,再执行自己的。
为什么?
子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据。
子类初始化之前,一定要调用父类构造方法先完成父类数据空间的初始化。
怎么调用父类构造方法的?
子类构造方法的第一行语句默认都是:super(),父类的空参构造,不写也默认存在,且必须在第一行。
如果想调用父类有参构造,必须手动写super进行调用。
(11)this、super使用总结
this:理解为一个变量,表示当前方法调用者的地址值;
super:代表父类存储空间。
this
练习一.带有继承结构的标准Javabean类
1.经理
成员变量:工号,姓名,工资,管理奖金
成员方法:工作(管理其他人),吃饭(吃米饭)
2.厨师
成员变量:工号,姓名,工资
成员方法:工作(炒菜),吃饭(吃米饭)
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 this.id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return this.salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public void Work() {
System.out.println("工作");
}
public void eat() {
System.out.println("吃米饭");
}
}
public class Manager extends Employee {
private double bouns;
public Manager() {
}
public Manager(String id, String name, double salary, double bouns) {
super(id, name, salary);
this.bouns = bouns;
}
public double getBouns() {
return this.bouns;
}
public void setBouns(double bouns) {
this.bouns = bouns;
}
public void Work() {
System.out.println("管理其他人");
}
}
public class Cook extends Employee {
public Cook() {
}
public Cook(String id, String name, double salary) {
super(id, name, salary);
}
public void Work() {
System.out.println("炒菜");
}
}
public class Test {
public Test() {
}
public static void main(String[] args) {
Manager m = new Manager("001", "张三", (double)10000.0F, (double)2000.0F);
PrintStream var10000 = System.out;
String var10001 = m.getId();
var10000.println(var10001 + " " + m.getName() + " " + m.getSalary() + " " + m.getBouns());
m.eat();
m.Work();
Cook c = new Cook();
c.setId("002");
c.setName("李四");
c.setSalary((double)5000.0F);
var10000 = System.out;
var10001 = c.getId();
var10000.println(var10001 + " " + c.getName() + " " + c.getSalary());
c.eat();
c.Work();
}
}
练习二.带有继承结构的标准Javabean类
在黑马程序员中有很多员工(Employee),按照工作内容不同分教研部员工(Teacher)和行政部员工(AdminStaff)
1.教研部根据教学的方式不同又分为讲师(Lecturer)和助教(Tutor)
2.行政部根据负责事项不同,又分为维护专员(Maintainer),采购专(Buyer)
3.公司的每一个员工都编号,姓名和其负责的工作
4.每个员工都有工作的功能,但是具体的工作内容又不一样。
public class Employee {
private String id;
private String name;
public Employee() {
}
public Employee(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public void Work() {
System.out.println("工作");
}
}
public class AdminStaff extends Employee {
public AdminStaff() {
}
public AdminStaff(String id, String name) {
super(id, name);
}
public void Work() {
System.out.println("行政部");
}
}
public class Maintainer extends AdminStaff {
public Maintainer() {
}
public Maintainer(String id, String name) {
super(id, name);
}
public void Work() {
System.out.println("维护");
}
}
public class Buyer extends AdminStaff {
public Buyer() {
}
public Buyer(String id, String name) {
super(id, name);
}
public void Work() {
System.out.println("采购");
}
}
public class Lecturer extends Teacher {
public Lecturer() {
}
public Lecturer(String id, String name) {
super(id, name);
}
public void Work() {
System.out.println("讲师");
}
}
public class Teacher extends Employee {
public Teacher() {
}
public Teacher(String id, String name) {
super(id, name);
}
public void Work() {
System.out.println("教研");
}
}
public class Tutor extends Teacher {
public Tutor() {
}
public Tutor(String id, String name) {
super(id, name);
}
public void Work() {
System.out.println("助教");
}
}
public class Test {
public Test() {
}
public static void main(String[] args) {
Lecturer l = new Lecturer("001", "张三");
PrintStream var10000 = System.out;
String var10001 = l.getId();
var10000.println(var10001 + " " + l.getName());
l.Work();
System.out.println("--------------------------");
Tutor t = new Tutor();
t.setId("002");
t.setName("李四");
var10000 = System.out;
var10001 = t.getId();
var10000.println(var10001 + " " + t.getName());
t.Work();
System.out.println("--------------------------");
Maintainer m = new Maintainer("003", "王五");
var10000 = System.out;
var10001 = m.getId();
var10000.println(var10001 + " " + m.getName());
m.Work();
System.out.println("--------------------------");
Buyer b = new Buyer();
b.setId("004");
b.setName("赵六");
var10000 = System.out;
var10001 = b.getId();
var10000.println(var10001 + " " + b.getName());
b.Work();
}
}
三.多态
1.什么是多态?
同类型的对象,表现出的不同形态。
2.多态的表现形式
父类类型 对象名称=子类对象;
3.多态的前提
(1).有继承关系
(2)有父类引用指向子类对象 Fu f= new Zi();
(3)有方法重写
4.多态的好处?
使用父类型作为参数,可以接收所有子类对象,体现多态的扩展性与便利。
5.多态调用成员的特点
变量调用:编译看左边,运行也看左边。
方法调用:编译看左边,运行看右边。
理解:调用成员变量:编译看左边,运行也看左边
编译看左边:javac编译代码的时候,会看左边的父类中有没有这个变量,如果有,编译成功,如果没有编译失败。
运行也看左边:java运行代码的时候,实际获取的就是左边父类中成员变量的值
调用成员方法:编译看左边,运行看右边
编译看左边:javac编译代码的时候,会看左边的父类中有没有这个方法,如果有,编译成功,如果没有编译失败。
运行看右边:java运行代码的时候,实际上运行的是子类中的方法。
6.多态调用成员的内存图解
7.多态的优势
(1)在多态形式下,右边对象可以实现解耦合,便于扩展和维护。
Person p=new student ();
p.work();//当业务逻辑发生改变时,后续代码无需修改
(2)定义方法的时候,使用父类型作为参数,可以接收所有子类对象,体现多态的扩展性与便利。
8.多态的弊端是什么?
不能使用子类的特有功能
怎么解决这一弊端呢?
使用instanceof关键字判断,然后使用强制类型转换。
9.引用数据类型的类型转换,有几种方式?
自动类型转换:Person p= new Student();
强制类型转换:Student s =(Student) p;
10.强制类型转换能解决什么问题?
可以转换成真正的子类类型,从而调用子类独有功能。
不能乱转,转换类型与真实对象类型不一致会报错
转换的时候用instanceof关键字进行判断
练习
public class Animal {
private int age;
private String color;
private String something;
public Animal() {
}
public Animal(int age, String color) {
this.age = age;
this.color = color;
}
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return this.color;
}
public void setColor(String color) {
this.color = color;
}
public void eat(String something) {
}
}
public class Cat extends Animal {
public Cat() {
}
public Cat(int age, String color) {
super(age, color);
}
public void catchMouse() {
System.out.println("猫在抓老鼠");
}
}
public class Dog extends Animal {
public Dog() {
}
public Dog(int age, String color) {
super(age, color);
}
public void lookHome() {
System.out.println("狗子在看家");
}
}
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 this.name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
public void keepPet(Animal animal, String something) {
if (animal instanceof Cat c) {
something = "鱼";
int var10001 = this.age;
System.out.println("年龄为" + var10001 + "岁的" + this.name + "养了一只" + animal.getColor() + "颜色的" + animal.getAge() + "岁的猫");
PrintStream var10000 = System.out;
var10001 = animal.getAge();
var10000.println(var10001 + "岁的" + animal.getColor() + "颜色的猫眯着眼睛侧着头吃" + something);
c.catchMouse();
} else if (animal instanceof Dog d) {
something = "骨头";
int var9 = this.age;
System.out.println("年龄为" + var9 + "岁的" + this.name + "养了一只" + animal.getColor() + "颜色的" + animal.getAge() + "岁的狗");
PrintStream var7 = System.out;
var9 = animal.getAge();
var7.println(var9 + "岁的" + animal.getColor() + "颜色的狗两只前腿死死抱住" + something + "猛吃");
d.lookHome();
}
}
}
public class Test {
public Test() {
}
public static void main(String[] args) {
Person person = new Person("老王", 30);
Animal dog = new Dog(2, "黑");
person.keepPet(dog, "骨头");
Person p2 = new Person("老李", 25);
Animal cat = new Cat(3, "灰");
p2.keepPet(cat, "鱼");
}
}
四.包
(1)什么是包?
包就是文件夹。用来管理各种不同功能的Java类,方便后期代码维护。
(2)包名的规则:公司域名反写+包的作用,需要全部英文小写,见名知意。 例如:com.itheima.domain
package com.itheima.domain;
(3)全类名,全限定名:包名+类名,例如:com.itheima.domain. Student
(4)使用其他类的规则
1.使用其他类时,需要使用全类名。
这样写太繁琐了,可以先导包,再使用
2.使用同一个包中的类时,不需要导包。
3.使用java.lang包中的类时,不需要导包,其他情况都需要导包。如使用String不需要导包
4.如果同时使用两个包中的同名类,需要用全类名。
五.final
(1).final:最终的,不可改变的
(2)修饰方法:表明该方法是最终方法,不能被重写
修饰类:表明该类是最终类,不能被继承
修饰变量:叫做常量,只能被赋值一次
(3)常量
1.常量:实际开发中,常量一般作为系统的配置信息,方便维护,提高可读性。
2.常量的命名规范:单个单词:全部大写
多个单词:全部大写,单词之间用下划线隔开
3.细节:final修饰的变量是基本类型,那么变量存储的数据值就不能发生改变。
final修饰的变量是引用类型,那么变量存储的地址值不能发生改变,对象内部可以改变。
public class Test {
public static void main(String[] args) {
final int a=10;
// a=20;//报错
System.out.println(a);
}}
class FU{
public final void show(){//什么时候会用呢?
//当方法是一种规则,我们不希望别人改变它时,会用
System.out.println("父类的show方法");
}
}
class Zi extends FU{
//public void show(){//会报错
// System.out.println("子类的show方法");
// }
}
public class Test {
public static void main(String[] args) {
final int a=10;
System.out.println(a);
//a=20;报错
//final修饰基本数据类型:记录的值不能改变
//final修饰引用数据类型:记录的地址值不会改变,内部的属性值还是可以改变
final Student s=new Student("张三",20);
//s=new Student();会报错,地址值不能改变
s.setName("李四");
s.setAge(30);//不会报错,属性值可以改变
System.out.println(s.getName()+":"+s.getAge());
//数组也是引用数据类型
final int []arr={1,2,3};
//arr=new int[10];报错
arr[0]=4;
arr[1]=5;
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
//核心:常量记录的数据是不能发生改变的
}
}
}
class Student{
private String name;
private int age;
public Student() {
}
public Student(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;
}
}
练习
常量的练习
将学生管理系统中用户的操作改写为常量的形式
六.权限修饰符
1.权限修饰符是用来控制一个成员能够被访问的范围的,可以修饰成员变量,方法,构造方法,内部类。
2.权限修饰符的分类
private,默认,protected,public
3.四种作用范围由小到大: private <空着不写< protected <public
4.权限修饰符的使用规则
实际开发中,一般只用private和public
成员变量私有
方法公开
特例:如果方法中的代码是抽取其他方法中共性代码,这个方法一般也私有,例如ArrayList中add方法中的grow方法。
七.代码块
1.代码块的分类:
局部代码块
构造代码块:1.写在成员位置的代码块
2.作用:可以把多个构造方法中重复的代码抽取出来
3.执行时机:我们在创建本类对象的时候会先执行构造代码块再执行构造方法
静态代码块:
格式:static{}
特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次
使用场景:在类加载的时候,做一些数据初始化的时候使用。
2.代码块的作用
局部代码块:
提前结束变量的生命周期(已淘汰)
构造代码块的作用:
抽取构造方法中的重复代码(不够灵活】
静态代码块的作用:
数据的初始化(重点)
八.抽象
1.分类:抽象方法和抽象类
2.概念:
抽象方法:将共性的行为(方法)抽取到父类之后,由于每一个子类执行的内容是不一样,所以,在父类中不能确定具体的方法体,该方法就可以定义为抽象方法。
抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类
3.抽象类和抽象方法的定义格式
抽象方法的定义格式:
public abstract 返回值类型 方法名(参数列表);
抽象类的定义格式:
public abstract class 类名{}
4.抽象类和抽象方法的注意事项
(1)抽象类不能实例化
(2)抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
(3)可以有构造方法
(4)抽象类的子类:要么重写抽象类中的所有抽象方法,要么是抽象类
5.意义:使子类形式统一
练习.编写带有抽象类的标准Javabean类
青蛙frog 属性:名字,年龄
行为:吃虫子,喝水
狗Dog 属性:名字,年龄
行为:吃骨头,喝水
山羊Sheep 属性:名字,年龄
行为:吃草,喝水
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("喝水中,勿扰。。。");
}
public abstract void eat();
}
public class Dog extends Animal{
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat(){
System.out.println("吃骨头");
}
}
public class Frog extends Animal{
public Frog() {
}
public Frog(String name, int age) {
super(name, age);
}
@Override
public void eat(){
System.out.println("吃虫子");
}
}
public class Sheep extends Animal{
public Sheep() {
}
public Sheep(String name, int age) {
super(name, age);
}
@Override
public void eat(){
System.out.println("吃草");
}
}
public class Test {
public static void main(String[] args) {
Animal a=new Dog();
d(a);//多态仍然能使用
Frog f=new Frog();
f.eat();
f.drink();
Dog d=new Dog();
d.eat();
d.drink();
Sheep sheep=new Sheep();
sheep.eat();
sheep.drink();
}
public static void d(Animal a){
a.eat();
}
}
九.接口
1.为什么要接口:接口是一种规则,是对行为的抽象,不是所有子类共有的属性,而是某几个子类共有的。
2.接口的定义和使用
接口用关键字interface来定义
public interface 接口名{}
接口不能实例化
接口和类之间是实现关系,通过implements关键字表示
public class 类名 implements 接口名{}
接口的子类(实现类):
要么重写接口中的所有抽象方法
要么是抽象类
3.注意
注意1:接口和类的实现关系,可以单实现,也可以多实现。
public class 类名 implements 接口名1,接口名2{
注意2:实现类还可以在继承一个类的同时实现多个接口。
public class 类名 extends 父类 implements 接口名1,接口名2
练习:编写带有接口和抽象类的标准Javabean类
青蛙:属性:名字,年龄
行为:吃虫子,蛙泳
狗:属性:名字,年龄
行为:吃骨头,狗刨
兔子:属性:名字,年龄
行为:吃胡萝卜
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("喝水中,勿扰。。。");
}
public abstract void eat();
}
public interface swim {
public void swimming();
}
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("吃骨头");
}
public void swimming(){
System.out.println("狗刨");
}
}
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("吃虫子");
}
public void swimming(){
System.out.println("蛙泳");
}
}
public class Rabbit extends Animal{
public Rabbit() {
}
public Rabbit(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("吃胡萝卜");
}
}
public class Test {
public static void main(String[] args) {
Frog f= new Frog();
f.eat();
f.swimming();
Dog d= new Dog();
d.eat();
d.swimming();
Rabbit r= new Rabbit();
r.eat();
}
}
4.接口中成员的特点
成员变量:只能是常量
默认修饰符:public static final
构造方法:没有
成员方法:只能是抽象方法
默认修饰符:public abstract
JDK7以前:接口中只能定义抽象方法。
JDK8的新特性:接口中可以定义有方法体的方法。
JDK9的新特性:接口中可以定义私有方法。
5.接口和类之间的关系
类和类的关系:继承关系,只能单继承,不能多继承,但是可以多层继承
类和接口的关系:实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
接口和接口的关系:继承关系,可以单继承,也可以多继承
练习:编写带有接口和抽象类的标准Javabean类
我们现在有乒乓球运动员和篮球运动员,乒乓球教练和篮球教练。
为了出国交流,跟乒乓球相关的人员都需要学习英语。
请用所有知识分析,在这个案例中,哪些是具体类,哪些是抽象类,哪些是接口?
乒乓球运动员:姓名,年龄,学打乒乓球,说英语
篮球运动员:姓名,年龄,学打篮球
乒乓球教练:姓名,年龄,教打乒乓球,说英语
篮球教练:姓名,年龄,教打篮球
public interface interEnglish {
public abstract void speakEnglish();
}
//将人定义为abstract,因为我不想让外界直接创建人的对象
//因为此时直接创建人的对象是没有意义的
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;
}
}
public abstract class Students extends person{
public Students() {}
public Students(String name , int age) {
super(name, age);
}
public abstract void Study();
}
public abstract class Coach extends person {
public Coach() {
}
public Coach(String name, int age) {
super(name, age);
}
public abstract void teach();
}
public class baskerballCoach extends Coach{
public baskerballCoach() {
}
public baskerballCoach(String name, int age) {
super(name, age);
}
@Override
public void teach(){
System.out.println("教打篮球");
}
}
public class basketballStudents extends Students{
public basketballStudents() {}
public basketballStudents(String name, int age) {
super(name, age);
}
@Override
public void Study(){
System.out.println("学打篮球");
}
}
public class tabletennisCoach extends Coach implements interEnglish{
public tabletennisCoach(){
}
public tabletennisCoach(String name, int age){
super(name, age);
}
@Override
public void teach(){
System.out.println("教打乒乓球");
}
@Override
public void speakEnglish(){
System.out.println("说英语");
}
}
public class tabletennisStudent extends Students implements interEnglish {
public tabletennisStudent() {
}
public tabletennisStudent(String name, int age) {
super(name, age);
}
@Override
public void Study(){
System.out.println("学打乒乓球");
}
@Override
public void speakEnglish(){
System.out.println("说英语");
}
}
public class Test {
public static void main(String[] args) {
tabletennisStudent ts=new tabletennisStudent("张三",20);
tabletennisCoach tc=new tabletennisCoach("李四",30);
basketballStudents bs=new basketballStudents("王五",25);
baskerballCoach bc=new baskerballCoach("赵六",35);
ts.Study();
ts.speakEnglish();
System.out.println(ts.getName()+" "+ts.getAge());
tc.teach();
tc.speakEnglish();
System.out.println(tc.getName()+" "+tc.getAge());
bs.Study();
System.out.println(bs.getName()+" "+bs.getAge());
bc.teach();
System.out.println(bc.getName()+" "+bc.getAge());
}
}
6.JDK8以后接口中新增的方法
(1)允许在接口中定义默认方法,需要使用关键字 default 修饰
作用:解决接口升级的问题
接口中默认方法的定义格式:格式:public default 返回值类型方法名(参数列表){}
范例:public default void show(){ }
接口中默认方法的注意事项:默认方法不是抽象方法,所以不强制被重写。但是如果被重写,重写的时候去掉default关键字。public可以省略,default不能省略
如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写
(2)允许在接口中定义定义静态方法,需要用static修饰
接口中静态方法的定义格式:
格式:public static 返回值类型方法名(参数列表){ }
范例:public static void show(){}
接口中静态方法的注意事项:
静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
public可以省略,static不能省略
7.JDK9新增的方法
接口中私有方法的定义格式:
格式:private 返回值类型方法名(参数列表){}
范例1:private void show(){}
格式2:private static 返回值类型方法名(参数列表){}
范例2:private static void method(){}
8.接口的应用
(1)接口代表规则,是行为的抽象。想要让哪个类拥有一个行为,就让这个类实现对应的接口就可以了。
(2)当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方式称之为接口多态。
十.适配器设计模式
1.概念:设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
2.目的:使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。
3.简单理解:设计模式就是各种套路。
4.适配器设计模式:解决接口与接口实现类之间的矛盾问题
5.什么时候用:当一个接口中抽象方法过多,但是我只要使用其中一部分的时候,就可以适配器设计模式
6.书写步骤:编写中间类XXXAdapter实现对应的接口,对接口中的抽象方法进行空实现,让真正的实现类继承中间类,并重写需要用的方法,为了避免其他类创建适配器类的对象,中间的适配器类用abstract进行修饰。
十一.内部类
类的五大成员:属性、方法、构造方法、代码块、内部类
1.什么是内部类?
在一个类的里面,再定义一个类。
举例:在A类的内部定义B类, B类就被称为内部类
2.什么时候用到内部类?
B类表示的事物是A类的一部分,且B单独存在没有意义。
比如:汽车的发动机,ArrayList的迭代器,人的心脏等等
3.内部类的访问特点
内部类可以直接访问外部类的成员,包括私有
外部类要访问内部类的成员,必须创建对象
public class Car {
String Name;
int age;
public void show(){
System.out.println("Name: " + Name);
System.out.println("Age: " + age);
//System.out.println(engineName);报错,外部类无法直接访问内部类
Engine e=new Engine();
System.out.println(e.engineName);
}
class Engine{
String engineName;
int engineAge;
public void shaow(){
System.out.println("Engine: " + engineName);
System.out.println("Engine: " + engineAge);
}
}
}
public class Test {
public static void main(String[] args) {
Car c=new Car();
c.Name="兰博基尼";
c.age=2;
c.show();
}
}
4.内部类的分类:
成员内部类,静态内部类,局部内部类,匿名内部类。
5.成员内部类:写在成员位置的,属于外部类的成员。
成员内部类可以被一些修饰符所修饰,比如: private,默认,protected,public,static等。
在成员内部类里面,JDK16之前不能定义静态变量,JDK 16开始才可以定义静态变量。
6.获取成员内部类对象的两种方式?
方式一:当成员内部类被private修饰时,在外部类编写方法,对外提供内部类对象
方式二:当成员内部类被非私有修饰时,直接创建对象。
Outer.Inner oi = new Outer().new Inner();
7.外部类成员变量和内部类成员变量重名时,在内部类如何访问?
System.out.println(Outer.this.变量名);
8.静态内部类
静态内部类是一种特殊的成员内部类,静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建对象。
创建静态内部类对象的格式:外部类名.内部类名 对象名= new 外部类名.内部类名();
调用非静态方法的格式:先创建对象,用对象调用
调用静态方法的格式:外部类名.内部类名.方法名();
9.局部内部类
(1)将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量。
(2)外界是无法直接使用,需要在方法内部创建对象并使用。
(3)该类可以直接访问外部类的成员,也可以访问方法内的局部变量。
10.匿名内部类
匿名内部类本质上就是隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置。
格式的细节:包含了继承或实现,方法重写,创建对象。整体就是一个类的子类对象或者接口的实现类对象
使用场景:当方法的参数是接口或者类时,以接口为例,可以传递这个接口的实现类对象,如果实现类只要使用一次,就可以用匿名内部类简化代码。