——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-
一、继承
1.继承的含义:
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。 多个类可以称为子类,单独这个类称为父类或者超类。
2.Java中表示继承的格式:
1)用关键字extends表示
2)格式:class 子类名 extends 父类名 {}
3.继承的好处:
1)提高了代码的复用性
2)提高了代码的维护性
3)让类与类产生了一个关系,是多态的前提
4.继承的弊端:
1)让类的耦合性增强。这样某个类的改变,就会影响其他和该类相关的类。
原则:低耦合,高内聚。
耦合:类与类的关系
内聚:自己完成某件事情的能力
2)打破了封装性
5.Java中继承的特点
1)Java中类只支持单继承
2)Java中可以多层(重)继承(继承体系)
6.继承的注意事项:
1) 子类不能继承父类的私有成员
2) 子类不能继承父类的构造方法,但是可以通过super去访问
3) 不要为了部分功能而去继承
7.什么时候使用继承呢?
1)继承体现的是:is a的关系。
2)采用假设法
8.Java继承中的成员关系
1)成员变量
子类的成员变量名称和父类中的成员变量名称不一样
子类的成员变量名称和父类中的成员变量名称一样,访问方式:
子类的方法访问变量的查找顺序:
在子类方法的局部范围找,有就使用。
在子类的成员范围找,有就使用。
在父类的成员范围找,有就使用。
找不到,就报错。
2)构造方法
子类的构造方法默认会去访问父类的无参构造方法,为了子类访问父类数据的初始化
父类中如果没有无参构造方法解决办法:
子类通过super去明确调用带参构造
子类通过this调用本身的其他构造,但是一定会有一个去访问了父类的构造
让父类提供无参构造
3)成员方法
子类的成员方法和父类中的成员方法名称不一样
子类的成员方法和父类中的成员方法名称一样,通过子类对象访问一个方法的查找顺序:
在子类中找,有就使用
在父类中找,有就使用
找不到,就报错
9.猫狗案例的分析和实现
packagecom.itheima;
//定义动物类
class Animal{
// 姓名
private String name;
// 年龄
private int age;
// 颜色
private String color;
public Animal() { }
public Animal(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
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 getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public void eat() {
System.out.println("吃饭");
}
}
// 定义猫类
class Cat extends Animal {
public Cat() { }
public Cat(Stringname, int age, String color) {
super(name,age, color);
}
public void catchMouse() {
System.out.println("抓老鼠");
}
}
// 定义狗类
class Dog extends Animal {
public Dog() { }
public Dog(String name, int age, String color) {
super(name, age, color);
}
public void lookHome() {
System.out.println("看家");
}
}
// 测试类
class ExtendsTest5 {
public static void main(String[] args) {
// 测试猫
// 方式1
Cat c1 = new Cat();
c1.setName("Tom");
c1.setAge(3);
c1.setColor("白色");
System.out.println("猫的名字是:" + c1.getName() + ";年龄是:" +c1.getAge()+ ";颜色是:" + c1.getColor());
c1.eat();
c1.catchMouse ();
System.out.println("---------------");
// 方式2
Cat c2 = new Cat("杰瑞", 5,"土豪金");
System.out.println("猫的名字是:" + c2.getName() + ";年龄是:" + c2.getAge() +";颜色是:" + c2.getColor());
c2.eat();
c2.catchMouse ();
// 测试狗
// 方式1
Dogd1 = new Dog();
d1.setName("John");
d1.setAge(5);
d1.setColor("黑色");
System.out.println("狗的名字是:" + d1.getName() + ";年龄是:" + d1.getAge() + ";颜色是:" +d1.getColor());
d1.eat();
d1.lookDoor();
System.out.println("---------------");
// 方式2
Dogd2 = new Dog("Smith", 7, "黄");
System.out.println("狗的名字是:" + d2.getName() + ";年龄是:" +d2.getAge() + ";颜色是:" + d2.getColor());
d2.eat();
d2.lookDoor();
}
}
二、多态
1.多态的描述:
事物存在的多种形态
2.多态的前提:
有继承或者实现关系。
有方法重写。
有父类或者父接口引用指向子类对象。
3.多态的分类:
具体类多态
class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
抽象类多态
abstract class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
接口多态
interface Fu {}
class Zi implements Fu {}
Fu f = new Zi();
4.多态中的成员访问特点
成员变量:编译看左边,运行看左边
构造方法:子类的构造都会默认访问父类构造
成员方法:编译看左边,运行看右边
静态方法:编译看左边,运行看左边
5.多态的好处与弊端:
1)好处:
提高代码的维护性(继承体现)
提高代码的扩展性(多态体现)
2)弊端:
父不能使用子的特有功能。现象:子可以当作父使用,父不能当作子使用。
6.多态中的转型
向上转型:从子到父
向下转型:从父到子
7.猫狗案例
/*
猫狗案例
*/
class Animal {
public void eat() {
System.out.println("吃饭");
}
}
class Dog extends Animal {
public voideat() {
System.out.println("狗吃肉");
}
public voidlookHome() {
System.out.println("狗看门");
}
}
class Cat extends Animal {
public voideat() {
System.out.println("猫吃鱼");
}
public void catchMouse(){
System.out.println("捉老鼠");
}
}
class DuoTaiTest {
public staticvoid main(String[] args) {
// 定义为狗
Animal a =new Dog();
a.eat();
System.out.println("--------------");
// 还原成狗
Dog d =(Dog) a;
d.eat();
d.lookDoor();
System.out.println("--------------");
// 变成猫
a = newCat();
a.eat();
System.out.println("--------------");
// 还原成猫
Cat c =(Cat) a;
c.eat();
c.catchMouse();
System.out.println("--------------");
// 演示错误的内容
// Dog dd =new Animal();
// Dog ddd= new Cat();
//ClassCastException
// Dog dd =(Dog)a;
}
}
三、抽象类
1.为什么用抽象类:
在定义方法声明一样,但是每个具体的对象在具体实现的时候内容不一样的共性方法的时,则不能给出具体的方法体。
而一个没有具体的方法体的方法是抽象的方法。在一个类中如果有抽象方法,该类必须定义为抽象类。
2.抽象类的特点:
抽象类和抽象方法必须用关键字abstract修饰
抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类
抽象类不能实例化
抽象类的子类:
是一个抽象类。
是一个具体类。这个类必须重写抽象类中的所有抽象方法。
3.抽象类的成员特点:
成员变量:有变量,有常量
构造方法:有构造方法
成员方法:有抽象,有非抽象
4.抽象类的几个小问题
1)抽象类有构造方法,不能实例化,那么构造方法有什么用?
用于子类访问父类数据的初始化
2)一个类如果没有抽象方法,却定义为了抽象类,有什么用?
为了不让创建对象
3)abstract不能和哪些关键字共存
final 冲突
private 冲突
static 无意义
5.猫狗案例
/*
猫狗案例
具体事物:猫,狗
共性:姓名,年龄,吃饭
分析:从具体到抽象
猫:
成员变量:姓名,年龄
构造方法:无参,带参
成员方法:吃饭(猫吃鱼)
狗:
成员变量:姓名,年龄
构造方法:无参,带参
成员方法:吃饭(狗吃肉)
因为有共性的内容,所以就提取了一个父类。动物。
但是又由于吃饭的内容不一样,所以吃饭的方法是抽象的,
而方法是抽象的类,类就必须定义为抽象类。
抽象动物类:
成员变量:姓名,年龄
构造方法:无参,带参
成员方法:吃饭();
实现:从抽象到具体
动物类:
成员变量:姓名,年龄
构造方法:无参,带参
成员方法:吃饭();
狗类:
继承自动物类
重写吃饭();
猫类:
继承自动物类
重写吃饭();
*/
//定义抽象的动物类
abstract class Animal {
// 姓名
private Stringname;
// 年龄
private intage;
public Animal(){
}
publicAnimal(String name, int age) {
this.name =name;
this.age =age;
}
public StringgetName() {
returnname;
}
public voidsetName(String name) {
this.name = name;
}
public intgetAge() {
returnage;
}
public voidsetAge(int age) {
this.age =age;
}
// 定义一个抽象方法
public abstractvoid eat();
}
// 定义具体的狗类
class Dog extends Animal {
public Dog(){
}
publicDog(String name, int age) {
super(name,age);
}
public voideat() {
System.out.println("狗吃肉");
}
}
// 定义具体的猫类
class Cat extends Animal {
public Cat(){
}
publicCat(String name, int age) {
super(name,age);
}
public voideat() {
System.out.println("猫吃鱼");
}
}
// 测试类
class AbstractTest {
public staticvoid main(String[] args) {
// 测试狗类
// 具体类用法
// 方式1:
Dog d = newDog();
d.setName("旺财");
d.setAge(3);
System.out.println(d.getName() + "---" + d.getAge());
d.eat();
// 方式2:
Dog d2 =new Dog("旺财", 3);
System.out.println(d2.getName() + "---" + d2.getAge());
d2.eat();
System.out.println("---------------------------");
Animal a =new Dog();
a.setName("旺财");
a.setAge(3);
System.out.println(a.getName() + "---" + a.getAge());
a.eat();
Animal a2 =new Dog("旺财", 3);
System.out.println(a2.getName() + "---" + a2.getAge());
a2.eat();
// 测试猫类
// 具体类用法
// 方式1:
Cat c = newCat();
c.setName("喵喵");
c.setAge(4);
System.out.println(c.getName() + "---" + c.getAge());
c.eat();
// 方式2:
Cat c2 =new Cat("喵喵", 4);
System.out.println(c2.getName() + "---" + c2.getAge());
c2.eat();
System.out.println("---------------------------");
Animal b =new Cat();
b.setName("喵喵");
b.setAge(4);
System.out.println(b.getName() + "---" + b.getAge());
b.eat();
Animal b2 =new Cat("喵喵", 4);
System.out.println(b2.getName() + "---" + b2.getAge());
b2.eat();
}
}
四、接口
1.接口概述:
从狭义的角度讲就是指java中的interface
从广义的角度讲对外提供规则的都是接口
2.接口的特点:
接口用关键字interface修饰:interface 接口名 {}
类实现接口用implements修饰:class 类名 implements 接口名 {}
接口不能实例化
接口的实现类:
是一个抽象类。
是一个具体类,这个类必须重写接口中的所有抽象方法。
3.接口的成员特点:
成员变量,只能是常量,默认修饰符:public static final
没有构造方法
成员方法,只能是抽象的,默认修饰符:public abstract
4.类与接口之间的关系:
类与类:继承关系,只能单继承,可以多层继承
类与接口:实现关系,可以单实现,也可以多实现。还可以在继承一个类的同时,实现多个接口
接口与接口:继承关系,可以单继承,也可以多继承
5.抽象类和接口的区别:
成员区别
抽象类:可以是常量也可以是变量
接口:只能是常量
关系区别:
类与类:继承
类与接口:实现关系,可以单实现,也可以多实现。
接口与接口:继承关系,可以单继承,也可以多继承
设计理念不同
抽象类:is a,抽象类中定义的是共性功能。
接口:like a,接口中定义的是扩展功能。
6.猫狗案例
/*
猫狗案例,加入跳高的额外功能
分析:从具体到抽象
猫:
姓名,年龄
吃饭,睡觉
狗:
姓名,年龄
吃饭,睡觉
由于有共性功能,所以,我们抽取出一个父类:
动物:
姓名,年龄
吃饭();
睡觉(){}
猫:继承自动物
狗:继承自动物
跳高的额外功能是一个新的扩展功能,所以我们要定义一个接口
接口:
跳高
部分猫:实现跳高
部分狗:实现跳高
实现;
从抽象到具体
使用:
使用具体类
*/
//定义跳高接口
interface Jumpping {
// 跳高功能
public abstractvoid jump();
}
// 定义抽象类
abstract class Animal {
// 姓名
private Stringname;
// 年龄
private intage;
public Animal(){
}
publicAnimal(String name, int age) {
this.name =name;
this.age =age;
}
public StringgetName() {
returnname;
}
public voidsetName(String name) {
this.name = name;
}
public intgetAge() {
returnage;
}
public voidsetAge(int age) {
this.age =age;
}
// 吃饭();
public abstractvoid eat();
// 睡觉(){}
public voidsleep() {
System.out.println("睡觉觉了");
}
}
// 具体猫类
class Cat extends Animal {
public Cat(){
}
publicCat(String name, int age) {
super(name,age);
}
public voideat() {
System.out.println("猫吃鱼");
}
}
// 具体狗类
class Dog extends Animal {
public Dog(){
}
publicDog(String name, int age) {
super(name,age);
}
public voideat() {
System.out.println("狗吃肉");
}
}
// 有跳高功能的猫
class JumpCat extends Cat implements Jumpping {
publicJumpCat() {
}
publicJumpCat(String name, int age) {
super(name,age);
}
public voidjump() {
System.out.println("跳高猫");
}
}
// 有跳高功能的狗
class JumpDog extends Dog implements Jumpping {
publicJumpDog() {
}
publicJumpDog(String name, int age) {
super(name,age);
}
public voidjump() {
System.out.println("跳高狗");
}
}
class InterfaceTest {
public staticvoid main(String[] args) {
// 定义跳高猫并测试
JumpCat jc= new JumpCat();
jc.setName("哆啦A梦");
jc.setAge(3);
System.out.println(jc.getName() + "---" + jc.getAge());
jc.eat();
jc.sleep();
jc.jump();
System.out.println("-----------------");
JumpCat jc2= new JumpCat("加菲猫",2);
System.out.println(jc2.getName() + "---" + jc2.getAge());
jc2.eat();
jc2.sleep();
jc2.jump();
}
}
五、内部类
1.内部类的定义:
把类定义在另一个类的内部,该类就被称为内部类。例如:把类B定义在类A中,类B就被称为内部类。
2.内部类的访问规则
可以直接访问外部类的成员,包括私有
外部类要想访问内部类成员,必须创建对象
3.内部类的分类
成员内部类
private 为了数据的安全性
static 为了访问的方便性
成员内部类不是静态的:
外部类名.内部类名 对象名 = new 外部类名.new 内部类名();
成员内部类是静态的:
外部类名.内部类名 对象名 = new 外部类名.内部类名();
局部内部类
局部内部类访问局部变量必须加final修饰。因为局部变量使用完毕就消失,而堆内存的数据并不会立即消失。所以,堆内存还是用该变量,而改变量已经没有了。
为了让该值还存在,就加final修饰。通过反编译工具我们看到了,加入final后,堆内存直接存储的是值,而不是变量名。
4.匿名内部类
是局部内部类的简化形式
前提存在一个类或者接口
格式:
new 类名或者接口名() {
重写方法;
}
本质:其实是继承该类或者实现接口的子类匿名对象
5.匿名内部类在开发中的使用
在开发的时候,会看到抽象类,或者接口作为参数。而这个时候,我们知道实际需要的是一个子类对象。
如果该方法仅仅调用一次,我们就可以使用匿名内部类的格式简化。
interface Person {
public abstract void study();
}
class PersonDemo {
public void method(Person p) {
p.study();
}
}
class PersonTest {
public static void main(String[] args) {
PersonDemo pd = new PersonDemo();
pd.method(new Person() {
public void study() {
System.out.println("好好学习,天天向上");
}
});
}
}
——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——