提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
一、类继承机制的目的
IDEA 官方下载页面,(官网地址为 https://www.jetbrains.com/idea/)
继承是类之间的关系,非对象与对象的关系,继承是面向对象语言的特征之一。其目的是一个类(父类)到另外一个类(子类)的功能的延续,即类的复制且延续的过程。
继承具有以下的限制:
1.一个类可以同时被多个类继承,一父多子
2.一个类只能有一个直接父类,java不支持多继承
3.继承具有传递性,祖父—>父亲—>儿子—>孙子
4.final关键字修饰的类不能被继承
类继承语法规则
【访问修饰符】 class 子类名称 extends 父类名称{ }
public class Computer {
public double count(double a,double b){
return a+b;
}
}
public class Watch extends Computer{
public void displayDateTime(){
System.out.println(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
}
}
二、继承中对象的创建
在父类构造器的创建时,之类也随之要创建构造器(即先要有父亲再有儿子)。相反子类构造器的创建也必须要有父类的构造器的创建。且子类需要用super关键字。创建子类对象时总是要先创建一个父类对象,默认子类的构造方法总是自动调用父类的无参构造方法。
public class Computer { //父类
private String name;
public Computer(String name) { //带参的构造器
this.name = name;
}
public Computer() { //无参构造器
}
}
public class Watch extends Computer { //子类
public Watch(String name) {
//System.out.println(name); //报错,super关键子必须位于子类构造器的第一行
super(name); //子类的构造器super关键字永远是指向调用父类中的构造器创建父类对象,里面的name则指向父类带name参的构造器
}
}
Watch watch = new Watch("联想"); //对象的创建
三、继承中资源限制
1.默认情况下父类的成员属性和方法都可以被子类继承
2.私有属性和方法无法在子类中直接访问
3.构造方法不能被继承
4.上转型对象不能访问子类中新添加的属性和方法
public class MobilePhone extends Computer{
public void message(String context){
System.out.println("通讯内容"+context);
}
}
public static void main(String[] args) {
Computer computer = new MobilePhone();//上转型对象(实例是子类的,类型是父类的)
System.out.println(computer.count(23,45));
//computer.message; //上转型对象不能调用子类的属性和方法
MobilePhone phone = new MobilePhone();
phone.message("喂喂");
((MobilePhone)computer).message("我是你的朋友");//上转型对象可以强制转换就可以用子类的方法和属性
}
5.final 修饰的方法不能在子类中重写
四、方法重写
方法重写是java语言多态的特性,必须满足以下条件:
1.在子类中,方法名称与父类方法名称完全相同
2.方法的参数个数和类型完全相同,返回类型完全相同
3.方法的修饰符访问级别不低于父类同名方法的访问级别
方法重写的限制条件:
1.final修饰的父类方法在子类不能被重写
2.static修饰的父类方法在子类中不能被重写,只能覆盖。(static的方法也是可以继承的)
快捷键:右键—>生成 —>方法重写(IDEA)
五、super关键字
super关键字与this关键字都代表对象。super关键字只能存在继承关系的子类当中,代表父类对象。
1.super关键字出现在子类构造器中只能标识调用父类构造器
public Watch(String name) {
//System.out.println(name); //报错,super关键子必须位于子类构造器的第一行
super(name); //子类的构造器super关键字永远是指向调用父类中的构造器创建父类对象
}
2.super关键字出现在子类方法中标识访问父类方法或属性
@Override
public double count(double a, double b) { //重写父类的方法
//return super.count(a, b);
double res = super.count(a,b); //super关键字在子类的实例方法中永远代表父类对象,从而访问父类资源
return a-b+res;
}
3.super不能用在static的方法中
六 、java抽象设计的理念
动物可以分为很多子类,比如老虎、兔子、袋鼠、鸟等子类。他们都可以有一种动作方法,就是奔跑。我们在父类(Animal)定义run方法就不大好定义,要定义的话要在每个子类进行方法的重写。那我们可以在父类的run方法里面放空,形成一个抽象的设计。
1.面向对象的核心思想
java的核心编程思想是面向对象,而面向对象编程思想是面向抽象。
2.抽象类的定义及特点
//定义更高层次的抽象组件类,从而可以在被继承时根据实际子类应用场景继续功能的实现
public abstract class Animal {
public abstract void run(); //抽象类中允许定义抽象方法也可以定义非抽象方法,可以用public和protected修饰,用private修饰。
}
抽象类的特点:
1)抽象类通常应该包含抽象方法,也可以包含非抽象方法
2)抽象类不能用final关键字修饰
3)抽象类自身不能够实例化,必须依赖子类进行创建
4)抽象类就是用来被继承的
3.抽象类的继承和创建对象
1)抽象类被非抽象类继承必须对所有抽象方法提供实现
public class Lion extends Animal {
@Override
public void run() {
//具体的功能,普通类继承抽象类需要进行方法的重写
}
}
2)重写类被抽象类继承可以不实现父类的抽象方法
//不报错,抽象子类可以不实现父类的抽象方法,也可以实现抽象方法,而且在抽象子类中可以继续添加新的抽象方法和非抽象方法
public abstract class Mammal extends Animal{
}
3)抽象类对象的实例化必须通过非抽象子类进行创建
public class Test {
//Animal animal = new Animal(); 报错
Animal animal2 = new Lion();
}
4)抽象类对象都是上转型对象
5)final修饰的方法不能在子类中被重写,抽象方法不能用final修饰
4.适配器(Adapter)
如何让一个抽象类的非抽象子类有选择性的实现父类的抽象方法而不必全部实现所有抽象方法?而适配器就是抽象子类不全部实现抽象类的抽象方法的一个桥梁。
1)为抽象类定义适配器类,对所有抽象方法提供空实现
2)非抽象子类继承适配器类,只要重写需要的父类方法
public class AnimalAdapter extends Animal{
//为抽象类提供适配器从而让普通抽象类的子类继承此适配器,避免必须所有抽象方法
@Override
public void run() {
}
@Override
public void hunting() {
}
}
public class Fish extends AnimalAdapter{
@Override
public void run() {
}
}
5.对象运行时的多态
所有的对象都是在JVM中管理的,JVM在运行时创建和使用某个对象的时候才能确定对象具体是哪种数据类型。例如,有一个Animal的抽象类有run的抽象方法,有Cat,Fish,Lion的子类继承Animal的抽象方法run。一个人Person类要饲养着三个动物定义三个方法raiseLion,raiseFish,raiseCat。在测试类TestRunTime需要建立每个动物的对象,但是在但是在Person类中定义的方法内的参数的数据类型直接是父类Animal的类型,三个方法变成了一个的方法使代码更为简洁。在TestRunTime类利用上转型对象创建三个动物的对象,直接把参数调到person对象的那个全方法当中。原本需要一个一个定义的代码,在Person类当中就定义了一个进行代替,实现了JVM在运行时才决定最终的数据类型是什么,实现对象运行时的多态。
1)运行时多态能够使设计应用程序更加灵活,易于扩展,代码简洁
2)运行时多态体现了java面向对象语言特性继承的优越性
public class Person {
private String name;
public void raiseLion(Lion lion){
System.out.println("养狮子");
lion.run();
}
public void raiseFish(Fish fish){
System.out.println("养鱼");
fish.run();
}
public void raiseCat(Cat cat){
System.out.println("养鱼");
cat.run();
}
//运行时才决定pet参数到底是什么对象
public void raiseAnimal(Animal pet){
pet.run();
}
}
public class TestRunTime {
public static void main(String[] args) {
Person xiaocui = new Person();
Animal cat = new Cat();
//xiaocui.raiseCat(cat);
Animal lion = new Lion();
//xiaocui.raiseLion(lion);
xiaocui.raiseAnimal(cat); //运行时多态
}
}
七 、接口
1.static关键字的详解
public class Student{
private static int age; //静态的变量
private double score; //非静态的变量
public static void main(String[] args){
//静态的变量
Student s1 = new Student();
System.out.println(Student.age); //类的变量,
System.out.ptintln(s1.score); //对象的变量
Student s2 = new Student();
s2.run(); //非静态方法
go(); //静态方法
}
//静态方法
public void run(){
go();
}
public static void go(){
}
}
public class Person
{
{
//代码块(匿名代码块)并不能去调用这个代码块,匿名代码块在对象创建的时候就创建了。赋初始值
System.out.println("匿名代码块");
}
static{
//静态代码块,只执行一次
System.out.println("静态代码块");
}
public Person(){ //构造器
System.out.println("构造方法");
}
public static void main(String[] args){
Person person1 = new Person();
System.out.println("=======");
Person person2 = new Person();
}
}
//执行的结果
静态代码块
匿名代码块
构造方法
===========
匿名代码块
构造方法
2.接口的定义与实现
一方面,有时候需要几个类需要派生出一个类。本身Java只能是单继承。这时接口,就可以得到多重继承得效果。另一方面,有时候必须从几个类中抽取出一些相同的行为特征,而他们之间又没有is-a的关系(子类is a 父类),仅仅是具有相同的行为特征而已。比如鼠标,键盘,打印机等都支持usb链接。下图是这样的描述:
/*
接口的使用
1.接口使用interface来定义
2.java中,接口和 类是并列的讲个结构
3.如何定义接口,定义接口中的成员
JDK8以后,除了可以定义全局变量和抽象方法,还可以定义静态方法和默认方法(default)
知识点1:接口中的静态方法,只能通过接口来调用
知识点2:通过实现类的对象,可以调用接口的默认方法.如果实现类重写了接口的默认方法,调用时的是重写的方法。
知识点3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法。那么子类没有重写此方法的情况下,默认调用的是父类中的同名同参数方法,(类优先原则)
知识点4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没有重写的此方法的情况下,报错-->接口冲突。必须需要我们重写.
method3(); //调用重写的方法
super.method3();//调用的是父类中的
CompareA.super.method3();//调用接口中的方法compareA是接口
4.接口中是不能定义构造器,意味着接口不可以实例化。
5.java开发中,接口通过让类去实现(implements)的方式来使用
如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以示例化
如果实现类没有覆盖接口中的所有的抽象方法,则此实现类还是一个抽象类
6.java类可以实现多个接口--->解决Java的单继承性
格式:class AA extents BB implemennts CC,DD,EE
7.接口和接口之间可以继承,而且可以多继承
格式:interface AA extents BB,CC
8.接口的具体使用,体现多态性
9.接口,实际上可以看作是一种规范
*/
public class InterfaceTest {
}
interface Flyable{
//全局常量(默认定义全局常量)
public static final int MAX_SPEED = 7900;//第一宇宙速度
int MIN_SPEED = 1; //省略了public static final
//抽象方法
public abstract void fly();
//省略了public abstract
void stop();
}
class plane implements Flyable{
@Override
public void fly() {
System.out.println("fly");
}
@Override
public void stop() {
System.out.println("stop");
}
}
接口的图解:
3.接口的应用
1)代理模式(proxy)
代理模式是java开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问。打个比方你要买一个房子,你可以选择自己去买,那这个叫做被代理类。还可以选择叫中介帮你去买房,这个中介叫做代理类。被代理类里面的有一定的操作,可以把他放在代理类当中,利用多态写一个方法。代理类除了有被代理类的方法还有自己的一些方法。形成一个代理的模式。
//java的应用:代理模式
public class NetWorkTest {
public static void main(String[] args) {
Server server = new Server();
ProxyServer proxyServer = new ProxyServer(server); //多态
proxyServer.browse();
}
}
interface NetWork{
public void browse();
}
//被代理类
class Server implements NetWork{
@Override
public void browse() {
System.out.println("真实的服务器访问网络");
}
}
//代理类
class ProxyServer implements NetWork{
private NetWork work;
public ProxyServer(NetWork work) {
this.work = work;
}
@Override
public void browse() {
check();
work.browse();
}
public void check(){
System.out.println("联网前的检查工作");
}
}
2)工厂模式(factory)
实现了创建者与调用者的分离,即将创建对象的具体过程屏蔽起来,达到提高灵活性的目的。其解决的是’分工‘的问题。工厂模式的分类:1.无工厂模式 2.简单工厂模式 3.工厂方法模式 4.抽象工厂模式
4.内部类
java中允许一个类的定义位于另外一个类的内部,前者称为内部类,后者成为外部类。意义:当一个事物的内部,还有一部分需要一个完整的结构又只为外部事物提供服务,那么整个内部的完整结构最后使用内部类。
/*
*
内部类的分类:成员内部类(静态的,非静态的) vs 局部内部类(方法内 代码内 构造器内)
成员内部类:
一方面,作为外部类的成员,
>调用外部类的结构
>可以被static修饰
另一方面,作为一个类 ->类内也可以定义方法 属性 构造器 ->可以被final修饰,表示此类不可以被继承
->可以被abstract修饰
关注一下三个问题
1.如何实例化内部类的对象
2.如何在成员内部类中区分调用外部类的结构
3.开发中局部内部类的使用
*/
public class InnerClassTest {
public static void main(String[] args) {
//创建Dog实例(静态的成员内部类)
Person.Dog dog = new Person.Dog();
dog.show();
//创建Bird实例(非静态的成员内部类)
// Person.Bird bird = new Person.Bird(); 错误的
Person p = new Person();
Person.Bird bird = p.new Bird();
bird.sing();
}
}
class Person{
String name;
int age;
public void eat(){
System.out.println("吃饭");
}
//成员内部类
static class Dog{
String name;
int age;
public void show(){
System.out.println("我是条狗");
}
}
class Bird{
String name;
public Bird(){
}
public void sing(){
System.out.println("鸟在唱歌");
}
public void display(String name){ //如何区分调用三个name
System.out.println(name); //方法参数的name
System.out.println(this.name); //内部类Bird的name
System.out.println(Person.this.name); //外部类person类的name
}
}
public void method(){
//局部内部类
class AA{
}
}
{
//局部内部类
class BB{
}
}
public Person(){
//局部内部类
class CC{
}
}
//返回一个实现Comparable接口的对象 局部内部类的使用
public Comparable getComparable(){
//方式1:
//创建一个实现了Comparable接口的类;局部内部类
class MyComparable implements Comparable{
@Override
public int compareTo(Object o) {
return 0;
}
}
return new MyComparable();
//方式2:创建了实现类当中匿名的实现对象
/*
return new Comparable() {
@Override
public int compareTo(Object o) {
return 0;
}
}
*/
}
}