目录
一.继承
1.定义
- 让类和类之间产生关系(父子类关系),子类可以直接使用父类中非私有的成员,私有成员无法直接使用。
- 父类中私有的成员,子类可以继承,但是不能直接访问
2.范例
- public class Zi extends Fu{}
- Fu: 是父类,也被称为基类、超类 zi:是子类,也被称为派生类
class 父类{
... //成员变量、成员方法
}
class 子类 extends 父类{
... //类体
}
①创建类的细节:
1)一个Java文件可以编写多个class
2)保证类和类之间是平级关系
3)只能有一个被public修饰
4)当父类子类不在一个包下,应该书写导包代码
public class ExtendsDemo1 {
public static void main(String[] args) {
Coder c = new Coder();
c.name ="张三";
c.age = 23;
c.salary = 12000;
}
}
class Employee {
String name;
int age;
double salary;
}
class Coder extends Employee {
}
class Manager extends Employee
{
}
②子类如何调用父类中私有的成员
调用set,get方法
public class extend {
public static void main(String[] args)
{
Coder c = new Coder();
c.setName("张三");
c.setAge(23);
c.setSalary(12000);
System.out.println(c.getName() + "---" + c.getAge() + "---" + c.getSalary());
}
}
class Employee {
private String name;
private int age;
private double salary;
public Employee() {
}
public Employee(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
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 double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
class Coder extends Employee{
}
class Manager extends Employee{
}
③优点
提高代码的复用性
④使用情况
类与类之间,存在共性的内容,并且产生了is a 的关系,就可以考虑使用继承来优化代码
3.super关键字
①案例
public class Fu {
int num = 10;
}
public class Zi extends Fu {
int num = 20;
public void method(){System.out.println(num);
}
public class Test {
public static void main(String[] args) {
Zi z = new Zi();
z.method();//根据就近原则,此时打印出的是子类的20
}
为了打印出父类中的成员,使用super关键字
public class ExtendsDemo2{
public static void main(String[] args) {
Zi z = new Zi();
z.method();
}
}
class Fu {
int num = 10;
}
class Zi extends Fu {
int num = 20;
public void method(){
System.out.println(num);//打印子类的变量10
System.out.println(super.num);//打印父类的变量20
}
}
②super 调用父类成员的省略规则
super.父类成员变量| super.父类成员方法()
被调用的变量和方法,在子类中不存在,super.可以直接省略的(建议不省略,明确是从父类还是从子类调用的成员)
class Coder extends Employee{
public Coder(){
}
public Coder(String name, int age, double salary)){
super(name,age,salary);//调用父类中的构造方法
}
@Override
public void work(){
System.out.println("姓名为:"+super.getName()+",年龄为:"
+super.getAge()+"工资为:"+super.getSalary()+"的程序员");
}
}
③this和super
//开闭原则 : 对功能扩展做开放, 对修改代码做关闭
public class test {
public static void main(String[] args){
A a1 = new A(1,2,3);
A a2 = new A(1,2,3,4);
}
}
class A{
int a;
int b;
int c;
int d;
public A()
{
}
public A(int a,int b,int c)
{
this.a = a;
this.b = b;
this.c = c;
}
public A(int a,int b,int c,int d)
{
this(a,b,c);//调用本类的方法,减少代码量
this.d = d;
}
}
4.方法重写和方法重载
①方法重载(overLoad) : 在同一个类中,方法名相同,参数不同,与返回值无关
参数不同: 类型不同,个数不同,顺序不同
②方法重写(override) : 在子父类当中,出现了方法声明一模一样的方法 (方法名,参数,返回值)
public static void main(String[] args) {
Son s = new Son();
s.method();//输出的是Son...method
}
class Father {
public void method() {
System.out.println("Father...method..");
}
}
class Son extends Father {
public void method() {
System.out.println("Son...method");
}
}
①判断是否为方法重写
在子类的方法前添加注解:@Override
如果没有报错,即为方法重写
②方法重写的使用场景
子类需要继承父辈的方法,但是需要在此基础上进行优化和增强
public class extend2 {
public static void main(String[] args)
{
Son s = new Son();
s.love();
}
}
class Father{
public void love()
{
System.out.println("送花");
System.out.println("送肉");
}
}
class Son extends Father{
@Override//判断是否为方法重写
public void love()
{
super.love();//保留父类的方法,在此基础上做改进,当不需要父类原有方法时,可以删除该条代码
System.out.println("送口红");
System.out.println("送衣服");//添加新的内容,改善父类方法
}
}
输出结果:
送花
送肉
送口红
送衣服
③方法重写注意事项
父类中私有方法不能被重写
子类重写父类方法时,访问权限必须大于等于父类
5.继承的特点
Java只支持单继承,不支持多继承,但支持多层继承
package dome2;
public class extend3 {
public static void main(String[] args) {
C c = new C();//C中的对象可以同时调用A和B中的方法
c.methodc();
c.methodB();
c.methodA();
}
}
class A {
public void methodA() {
System.out.println("A...");
}
}
//B为A的子类
class B extends A {
public void methodB() {
System.out.println("B...");
}
}
//C为B的子类
class C extends B {
public void methodc() {
System.out.println("C...");
}
}
①继承中的成员访问特点——构造方法
1.构造方法不能被子类继承,子类需要手动输入构造方法
原因:构造方法名和类名要求一致
2.子类初始化之前,需要先对父类进行初始化
原因:子类中可能要用到父类中的数据
因此:子类需要访问父类的空参构造方法
public class extend2 {
public static void main(String[] args) {
Zi z1 = new Zi();
Zi z2 = new Zi(10);
}
}
class Fu {
public Fu() {
System.out.println("Fu类的空参构造方法");
}
public Fu(int num){
System.out.println("Fu类的带参构造方法...");
}
}
class Zi extends Fu {
public Zi() {
System.out.println("Zi类的空参构造方法");
}
public Zi(int num){
System.out.println("Zi类的带参构造方法...");
}
}
输出结果:
Fu类的空参构造方法
Zi类的空参构造方法
Fu类的空参构造方法
Zi类的带参构造方法...
在所有构造方法的第一行代码,都默认隐藏了一句话 super();通过这句代码,访问父类的空参数构造方法
细节: Java当中所有的类(处理object类),都直接或者间接的继承到了 object 类
②继承中构造方法执行流程——内存图解
6. 继承综合案例
public class extend {
public static void main(String[] args)
{
Coder c = new Coder("张三",23,15000);
c.work();
Manager m = new Manager("李四",24,18000,5000);
m.work();
}
}
-----------------------------------------------------------------------------------------
class Employee {
private String name;
private int age;
private double salary;
public void work(){
System.out.println("正在工作");
}
public Employee(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public Employee() {
}
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 double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
-------------------------------------------------------------------
class Coder extends Employee{
//子类要单独创建空参和带参的构造方法
public Coder(){
}
public Coder(String name, int age, double salary)){
super(name,age,salary);
}
@Override
public void work(){
System.out.println("姓名为:"+super.getName()+",年龄为:"
+super.getAge()+"工资为:"+super.getSalary()+"的程序员");
}
}
---------------------------------------------------------------------
class Manager extends Employee {
//父类中没有的成员变量,子类要单独创建,并写出set,get方法
private double bones;
public Manager(){
}
public Manager(String name, int age, double salary)){
super(name,age,salary);
}
public double getBones()
{
return bones;
}
public double setBones(double bones){
this.bones = bones;
}
@Override
public void work(){
System.out.println("姓名为:"+super.getName()+",年龄为:"
+super.getAge()+"工资为:"+super.getSalary()+"奖金为:"+bones+"的项目经理在分配任务");
}
}
6.final关键字
final : 修饰符,可用于修饰方法,类,变量
①特点
修饰方法: 表明该方法是最终方法,不能被重写
修饰类: 表明该类是最终类,不能被继承
注:当类中所有方法都是final修饰时,可直接用final修饰类
修饰变量: 表明该变量是常量,不能再次被赋值
基本数据类型:数据值不可改变
引用数据类型:地址值不可改变,但是内容可以改变
②final修饰成员变量的注意事项
1. final修饰成员变量,不允许修饰默认值
2. final修饰成员变量的初始化时机
1) 在定义的时候直接赋值
2) 在构造方法中完成赋值
③ final修饰变量的命名规范
- 如果变量名是一个单词,所有字母大写max MAX
- 如果变量名是多个单词, 所有字母大写,中间使用下划线分割 maxValue MAX_VALUE7.
7.包
包本质来说就是文件夹,用来管理类文件的
①建包的语法格式
package 公司域名倒写技术名称。报名建议全部英文小写,且具备意义
package com.itheima.domain;
public class Student {}
3.建包语句必须在第一行,一般IDEA工具会帮助创建
②导 包
相同包下的类可以直接访问,不同包下的类必须导包,才可以使用!
导包格式:import 包名.类名;
假如一个类中需要用到不同类,而这个两个类的名称是一样的,那么默认只能导入一个类,另一个类要带包名访问。
package com.itheima.c;
import com.itheima.a.Student;
public class Test {
public static void main(String[] args) {
Student stul = new Student();
stu1.eat();
// 使用全类名创建对象 : 包名 + 类名
com.itheima.b.Student stu2 = new com.itheima.b.Student();
stu2.sleep();
}
}
二.抽象类和抽象方法
1.抽象类的概念
抽象方法: 将共性的行为(方法)抽取到父类之后,发现该方法的实现逻辑无法在父类中给出具体明确,该方法就可以定义为抽象方法。
抽象类: 如果一个类中存在抽象方法,那么该类就必须声明为抽象类
abstract class Animal {
public abstract void eat();//父类无法描述确切的行为,因此要构造抽象方法
}
class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");//重写父类的方法
}
}
class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃肉");//重写父类方法
}
}
2.抽象类的注意事项 :
1. 抽象类不能实例化(不能创建对象)
- 如果抽象类允许创建对象,就可以调用内部没有方法体的抽象方法了
2.抽象类存在构造方法
- 交给子类,通过super进行访问
3.抽象类中可以存在普通方法
- 可以让子类继承到继续使用
4.抽象类的子类
1). 要么重写抽象类中的所有抽象方法
2). 要么是抽象类
3.抽象类和抽象方法的定义格式
抽象方法的定义格式:
public abstract 返回值类型 方法名(参数列表)
示例:
public abstract void eat();
抽象类的定义格式:
public abstract class 类名{}
abstract class Animal{}
三.接 口
1.接口介绍
接口:体现的思想是对规则的声明,Java中的接口更多体现的是对行为的抽象。接口中只有抽象方法。
2.定义接口
1.接口用关键字interface来定义
public interface 接口名 {}
2.接口不能实例化(不能创建对象)
3.接口和类之间是实现关系,通过implements关键字表示
public class 类名 implements 接口名 {}
3.接口的子类(实现类)
要么重写接口中的所有抽象方法
要么是抽象类(不建议)
public class interfaceTest {
public static void main(String[] args) {
InterImpl A1 = new InterImpl();//接口不能创建对象
A1.method();
A1.show();
}
}
interface Inter{
public abstract void show();//接口中全部是抽象方法
public abstract void method();
}
class InterImpl implements Inter{
//子类必须重写方法
@Override
public void show() {
System.out.println("show...");
}
@Override
public void method() {
System.out.println("method...");
}
}
4.接口中的成员特点
①成员变量
只能是常量;
默认修饰符public,static,final,三者顺序没有要求
②构造方法
没有
③成员方法
只能是抽象方法
默认修饰符: publrc abstract
关于接口中的方法,JDK8 和 JDK9 中有一些新特性
5.类和接口之间的各种关系
①类和类的关系
继承关系,只能单继承,但是可以多层继承
②类和接口的关系
实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
③接口和接口的关系
继承关系,可以单继承,也可以多继承
public class interTest2 {
}
class Fu{
public void show(){
System.out.println("show...");
}
}
//接口中方法名可以一样,因为都没有具体描述,不会冲突
interface A{
public void show();
}
interface B{
public void show();
}
class son extends Fu implements A,B {
//子类不需要重写接口中的方法,因为父类中存在同名方法,可以直接从父类中继承
}
6.抽象类和接口的对比
①成员变量
抽象类 : 可以定义变量,也可以定义常量
接口:只能定义常量
②成员方法
抽象类 : 可以是定义具体方法,也可以定义抽象方法
接口:只能定义抽象方法
③构造方法
抽象类:有
接口:没有
④功能
抽象类:对事物做抽象(描述事物)
接口 :对行为抽象 (制定规则),使代码更规范
7.JDK8和JDK9接口的新特性
<一>JDK8版本接口特性:
1.允许定义非抽象方法,需要加入default关键字
- 作用: 解决接口的升级问题
- 注意事项:
1.public可以省略,但是default不能省略
2.默认方法,实现类是允许重写的,但是需要去掉default关键字
3.如果实现了多个接口, 多个接口中存在相同的默认方法, 实现类必须重写默认方法
2.允许定义静态方法
- 理解: 既然接口已经允许方法带有方法体了,干脆也放开静态方法,可以类名调用
- 注意事项 :
1.public可以省略,但是static不能省略
2.接口中的静态方法, 只允许接口名进行调用,不允许实现类通过对象调用
public class interfaceTest {
public static void main(String[] args) {
AInterImpl a = new AInterImpl();
a.method();
}
}
interface A{
//加上default关键字,可以创建非抽象方法
default void method(){
System.out.println("A...method");
}
}
interface Inter{
public abstract void show();
public abstract void print();
default void method(){
System.out.println("Inter...method");
}
}
class AInterImpl implements Inter,A{
@Override
public void show() {
System.out.println("AInterImpl...show...");
}
@Override
public void print() {
System.out.println("AInterImpl...print...");
}
@Override
public void method() {
Inter.super.method();//不能直接用super调用接口的方法,要加上接口名
A.super.method();
}
}
<二>JDK9版本接口特性:
接口中允许定义私有方法
四.多 态
1.多态的介绍
同一个行为具有多个不同表现形式或形态的能力
示例:
public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入: 1.国内订单 2.国外订单");
//创建一个接口型变量,存在两个不同的接受类
OrderService orderService = null;
int choice = sc.nextInt();
switch (choice) {
case 1:
// 创建国内订单的业务类
orderService = new OrderServicelmpl();
break;
case 2:
// 创建国外订单的业务类
orderService = new OrderoverseasServicelmpl();
break;
}
//方法相同,但创建对象不同,运行结果不同
orderService.create();
orderService.findOne();
orderService.findList();
orderService.cancel();
orderService.finish();
orderService.paid();
}
}
2.多态的前提 :
1)有继承 / 实现关系
2)有方法重写
3)有父类引用指向子类对象:
①对象多态
Animal a1 = new Dog();
Animal a2 = new Cat();
好处: 方法的形参定义为父类类型,这个方法就可以接收到该父类的任意子类对象了
②行为多态
好处:同一个方法,具有多种不同表现形式,或形态的能力
public class extend2 {
public static void main(String[] args) {
//Dog dog1 = new Dog();子类引用指向子类对象
Animal a1 = new Dog();//父类引用指向子类对象
Animal a2 = new Cat();
useAnimal(new Dog());
useAnimal(new Cat());
}
public static void useAnimal(Animal a) {
a.eat();//传入不同对象,输出结果不同
}
}
abstract class Animal {
public abstract void eat();
}
class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃骨头");
}
}
3.多态的成员访问特点
1. 成员变量 : 编译看左边(父类),运行看左边(父类)
在编译的时候,会检查父类中有没有这个变量
没有 : 编译出错
有 : 编译通过,运行时使用父类中的变量值
2. 成员方法 : 编译看左边(父类),运行看右边(子类)
在编译的时候,会检查父类中有没有这个方法
没有 : 编译出错
有 : 编译通过,但是运行的时候,一定会执行子类的方法逻辑
原因: 担心你调用的方法,在父类中是一个抽象方法
示例:
public class interTest2 {
public static void main(String[] args) {
Fu F = new Zi();
System.out.println(F.num);//输出父类成员10
F.show();//执行子类方法
}
}
class Fu{
int num = 10;
public void show(){
System.out.println("Fu...show...");
}
}
class Zi extends Fu{
int num = 20;
@Override
public void show(){
System.out.println("Zi...show...");
}
}
3.多态创建对象,调用静态成员 :
静态的成员,推荐类名进行调用
细节:静态的成员,可以使用对象名调用,但这是一种假象
生成字节码文件后,会自动将对象名调用,改成类名调用
4.多态的好处和弊端
多态的好处:提高了程序的扩展性
多态的弊端:不能使用子类的特有成员,父类中没有定义该成员时,编译无法通过
5.多态的转型
1.概述:如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException
2.解决方法:
关键字 instanceof
使用格式:
对象名 instanceof 类型
判断一个对象是否是一个类的实例通俗的理解:
判断关键字左边的对象,是否是右边的类型,返回boolean类型结果
6. 案例:模拟支付接口
interface Payment {
void pay(double money);
}
-----------------------------------------------------------------------------------------
public class test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请选择支付方式: 1,支付平台支付 2,银行卡网银支付 3,信用卡快捷支付");
int choice = sc.nextInt();
Payment payment = null;
switch (choice) {
case 1:
payment = new PlatformPaymentimpl();
break;
case 2:
payment = new BankcardPaymentImpl();
break;
case 3:
payment = new CredicardPaymentImpl();
break;
}
System.out.println("请输入您的支付金额:");
double money = sc.nextDouble();
payment.pay(money);
}
}
---------------------------------------------------------------------------------------
public class BankcardPaymentImpl implements Payment {
@Override
public void pay(double money) {
System.out.println("通过银行卡网银支付了:"+money+"元");
}
}
-----------------------------------------------------------------------------------------
public class CredicardPaymentImpl implements Payment{
@Override
public void pay(double money) {
System.out.println("通过信用卡支付:"+money);
}
}
-----------------------------------------------------------------------------------------
public class PlatformPaymentimpl implements Payment {
@Override
public void pay(double money) {
System.out.println("通过支付平台支付了:"+money+"元");
}
}
五.代码块
1.定义:
使用{}括起来的代码被称为代码块
2.分类
1.局部代码块
位置:方法中定义
作用:限定变量的生命周期,及早释放,提高内存利用率构造代码块
2.构造代码块
位置:类中方法外定义
特点:每次构造方法执行的时候,都会执行该代码块中的代码,并且在构造方法执行前执行
作用:将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性
3.静态代码块
位置:类中方法外定义
特点:需要通过static关键字修饰,随着类的加载而加载,并且只执行一次
作用:在类加载的时候做一些数据初始化的操作