抽象类
抽象类:就是一个抽象的事物,没有具体到具体的东西
例如:动物就可以定义成抽象类,因为没有定义到具体的动物
关键字:abstract
友情提示:当一个类中有抽象方法,那么这个类一定是抽象类,但是当一个类是抽象类时,类中不一定都是抽象方法,也可以有普通方法。
抽象类的子类:
1)当子类跟父类一样都是抽象类的时候,那么将会毫无意义
因为抽象类不能创建对象,所以将无法调用任何成员。
2)当子类是具体类的时候,必须实现父类中的抽象方法(也就是通过方 法重写实现父类中的抽象方法)
例如:
package com.TexTDome;
abstract class Person{ //抽象类的格式
public abstract void method(); //抽象类的方法格式
}
class Student extends Person{
@Override
public void method() { //必须进行方法重写,否则就会报错
System.out.println("xxx");
}
}
抽象类的特点:
1)成员变量:
在抽象类中可以是变量,也可以是常量
例如:
变量:int num=10;
常量:public final int num=100;
2)构造方法:
可以有无参构造,也可以有有参构造
3)成员方法:
可以有抽象方法,也可以有非抽象方法
abstract在方法中关键字和哪些关键字是冲突的?
a) abstract和private
b) abstract和final
c) abstract和static
抽象类的练习:
package com.textDome2;
/**
* @author 杰哥
* 简版猫狗案例
*/
//抽象类
abstract class Animal {
private String name;
private int age;
public Animal() {
super();
}
public Animal(String name, int age) {
super();
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();//抽象方法
}
//Dog类
class Dog extends Animal{
public Dog() {
super();
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
}
//特有功能
public void method() {
System.out.println("狗还会看门");
}
}
//测试类
public class abstractText {
public static void main(String[] args) {
//多态方式
Animal a=new Dog() ;
a.eat();
a.setName("tom");
a.setAge(3);
//当你想调用Dog类中的特有功能时,可以使用多态中的向下转型,在多态中有提及
System.out.println(a.getName()+a.getAge());
//狗类无参及有参方式
Dog d=new Dog();
d.setName("baby");d.setAge(4);
System.out.println(d.getName()+d.getAge());
Dog d1=new Dog("dj",5);
System.out.println(d1.getName()+d1.getAge());
}
}
其中的理解都在代码中的注释里
接口
接口:就是事物的扩展功能(例如跳高猫中的jump)
关键字:interface
格式:interface 接口名{
(抽象功能)public abstract void jump(); //切记接口中的方法都是抽象方法
}
接口的子实现类
格式:class 类名impl implement接口类名{
}
接口的子类如果是抽象类的话,那将和抽象类一般毫无意义
接口的特点:
成员变量:定义之后他就是一个常量,不能更改变量在接口中的默认符是:public static final
构造方法:接口不存在构造方法
成员方法:全部都是抽象方法
默认符是:public abstract
接口与接口之间的关系:继承关系
下面来看个例子:
package com.textDome2;
interface Jump{
int num=23;
public abstract void method();
/*public void show() {
//普通成员方法在接口中会报错
}*/
/*public Jump() {
//这里系统会报错
}*/
}
class babyimpl implements Jump{
@Override
public void method() {
System.out.println("练习练习");
}
}
public class interfaceDome {
public static void main(String[] args) {
Jump j=new babyimpl();
//j.num=34; 在这里系统也会报错
System.out.println(j.num);
}
}
友情提示:
在接口里写抽象方法时,public abstract 可以省略不写,但是在抽象类中必须要声明出来。
接口的子类可以实现多个接口
接口之间也可以互相继承,甚至可以多个继承
例如:class 子类impl implement 接口类1,接口类2...{
}
接下来总结一下接口与抽象类的区别?
成员的区别:
成员变量:
接口中是常量不能改变(public static final int num=12)
抽象类中有常量有变量(常量:final int num=12;变量int num=23)
构造方法:
接口中没有构造方法
抽象类中有构造方法(无参和有参)
成员方法:
接口中都是抽象方法
抽象类中不全是抽象方法,还有普通方法
类与类、类与接口、接口与接口:
类与类:之间存在继承,只能单继承,不能多继承
类与接口:存在实现接口的功能,可以实现多个接口
接口与接口:可以存在继承关系,可以实现多继承
形式参数和返回值的问题
先来看形式参数:
当形式参数是具体类的时候:
package com.textDome2;
class Cat{
public void explode2() {
System.out.println("意思是爆炸");
}
}
class Dog{
public void emerge(Cat a) {
System.out.println("好好学习,天天向上");
}
}
public class Dome3 {
public static void main(String[] args) {
Dog d=new Dog();
Cat a=new Cat();
d.emerge(a);
}
}
直接创建两个类的对象,调用其中的方法
当形式参数是抽象类的时候:
package com.textDome2;
//当形式参数是抽象类的时候
abstract class head{
public void speak(){
System.out.println("她的声音很好听");
}
}
class text{
public void love(head h) {
System.out.println("她就是迪丽热巴");
}
}
class foot extends head{
}
public class DomeText4 {
public static void main(String[] args) {
text t=new text();
head h=new foot();
t.love(h);
}
}
查看上例,因为抽象类不可以创建对象,所以我们可以通过他的子类来实现,在main方法中首先第一步:创建text类的对象,因为要去调用love方法
第二步:当调用了形式变量中的h后,因为h是虚拟的,所以我们需要去实现它,通过多态去使h具体化,然后就可以去调用了
当形式参数是接口时:
package com.textDome2;
//当形式参数是接口时
interface hello{
public abstract void word();//切记接口中方法是抽象方法
}
class bird{
public void red(hello h) {
System.out.println("hello everyone");
}
}
class bedimpl implements hello{
@Override
public void word() {
}
}
public class DomeText5 {
public static void main(String[] args) {
bird b=new bird();
hello h=new bedimpl();
b.red(h);
}
}
步骤和思路跟抽象类是一样的
返回值的问题
当返回值是具体类的时候:
package com.textDome2;
class Person{
public void method() {
System.out.println("迪丽热巴最漂亮");
}
}
class PersonDome{
public Person show() {
return new Person();
}
}
public class Dometext {
public static void main(String[] args) {
//Person p=new Student();
PersonDome pd=new PersonDome();
Person p=pd.show();
p.method();
}
}
当返回值是类的时候,创建该类的对象
return new person 可以写成person p=new person();return p;
然后在主函数中思路和形式参数是一样的
当返回值是抽象类的时候:
package com.textDome2;
abstract class Person1{
public void urgent() {
System.out.println("urgent的意思是急迫,紧迫");
}
}
class PersonDome1{
public Person1 explode() {
return new Teacher1();
}
}
class Teacher1 extends Person1{
}
public class DomeText1 {
public static void main(String[] args) {
PersonDome1 d=new PersonDome1();
Person1 p= d.explode();
p.urgent();
}
}
在这里Person1 p= d.explode();因为有继承的关系
返回值是子类所以根据多态的关系(person1 p=new Teacher1()),所以会写成这样。思路还是不变的
当返回值是接口时:
package com.textDome2;
interface Animal{
void study();
}
class Dome{
public Animal good() {
return new catimpl();
}
}
class catimpl implements Animal{
@Override
public void study() {
System.out.println("迪丽热巴美得不像话");
}
}
public class DomeText2 {
public static void main(String[] args) {
Dome d=new Dome();
Animal a=d.good();
a.study();
}
}
思路和步骤跟抽象类是一样的,注意的是接口的子实现类要重写接口的抽象方法,不然就会报错
内部类
内部类分为成员内部类和局部内部类,还有匿名内部类。
成员内部类就是在一个类的成员位置,成员内部类可以访问外部类的任何成员,包括私有
当外部类想访问内部类的成员时,就需要创建内部类的类方法进行访问了
例如:
package com.textDome2;
//内部类
class number{
private int a=34;
class one{
public void two() {
System.out.println(a);//内部类可以随意访问外部类的成员,包括私有变量
}
}
public void three() {
one o=new one(); //在外部类的成员方法中创建内部类的对象
o.two();
}
}
public class DomeText7 {
public static void main(String[] args) {
number n=new number();
n.three();
}
}
除了这种方法外,我们还有一种直接访问的方法
格式是:外部类名.内部类名 对象名=new外部类名().new内部类名();
这样就不用在外部类的成员方法中创建内部类的对象了
但是切记内部类的成员方法一定是非静态的,否则就会报错
例如:
package com.textDome2;
//内部类
class number{
private int a=34;
class one{
public void two() {
System.out.println(a);//内部类可以随意访问外部类的成员,包括私有变量
}
}
}
public class DomeText7 {
public static void main(String[] args) {
number.one q=new number().new one();
q.two();
}
}
当内部类被private修饰时,外部类就无法访问,这样保证了数据的安全性
除了private外,还有static这个修饰符
当内部类被static修饰时,要想访问外部类的变量时,外部类的变量必须静态修饰
例如:
package com.textDome2;
//内部类
class number{
private static int a=34; //外部类变量也必须用静态修饰
static class one{
public void two() {
System.out.println(a);//静态修饰内部类时,访问外部类变量 }
}
}
public class DomeText7 {
public static void main(String[] args) {
//静态修饰内部类后,访问格式变成:外部类名.内部类名 对象名=new 外部类名.内部类名();
number.one q=new number.one();
q.two();
}
}
所以需要我们认真观察。
局部内部类:就是在外部类成员方法中的局部位置
局部内部类跟成员内部类一样都可以访问外部类的任何成员包括私有
当局部内部类访问局部变量时,会不会报错?
在jdk1.7版本会报错,但是jdk1.8版本优化改进后就不会报错了
例如:
package com.textDome2;
class color{
private int b=67;
public void black() {
final int num=34;//jdk1.7版本如果不写final,这里就会报错
class white{
public void green() {
System.out.println(b);
System.out.println(num);
}
}
}
}
因此这个问题需要我们知道,在面试的时候有可能会考。
匿名内部类
匿名内部类:前提必须是有一个类或者一个接口,这个类可以是抽象类也可以是具体类
格式:
New 类名或者接口名{
方法重写();
}
例如:
package com.TextDome3;
interface animal{
public abstract void show();
public abstract void method();
}
class Dog{
public void Door() {
animal a=new animal(){
@Override
public void show() {
System.out.println("迪丽热巴的美");
}
@Override
public void method() {
System.out.println("无人能及");
}
};
a.show();
a.method();
}
}
public class Dome01 {
public static void main(String[] args) {
Dog d=new Dog();
d.Door();
}
}
在上例中是因为需要调用两个方法,为了方便直接在匿名内部前定义了外部接口的方法名,不用我们new animal(){
.....
}.method();
new animal(){
.......
}.show(); 去一个一个调用了。
当类是抽象类的时候:
package com.TextDome3;
//当类是抽象类时
abstract class Person1{
public abstract void play();
}
class Teacher{
public void teach(Person1 p) {
p.play();
}
}
public class Dome03 {
public static void main(String[] args) {
Person1 p=new Person1() {
public void play() {
System.out.println("喜欢玩游戏");
}
};
p.play();
}
}
这个和之前形式参数是抽象类的思路大体是一致的,就是在匿名内部类的时候,运用了方法重写,重写了类中的抽象方法