------- android培训、java培训、期待与您交流! ----------
一、 抽象类
(1)抽象:把多个类中的共性的内容进行抽取,抽取后就能形成一个继承体系。但是,在今天的案例中,方法的声明相同,方法体不同,这样的抽取后,在父类中定义的时候,是不能写方法体的,这样的方法要想被java识别,就必须被标记为抽象的。如果一个类有抽象方法,那么该类肯定是抽象类。反之,抽象类中不一定有抽象方法。
抽象类的由来:
多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。
例如:狼和狗都有吼叫的方法,可是吼叫内容是不一样的。所以抽象出来的犬科虽然有吼叫功能,但是并不明确吼叫的细节。
(2)格式:
抽象方法只有方法声明,没有方法体,定义在抽象类中。
格式:修饰符 abstract 返回值类型 函数名(参数列表);
(2)好处:
A:抽象类中可以有成员变量和非抽象方法,也可以实现代码的复用。
B:抽象类强制要求继承他的子类必须完成某些功能。
(3)成员特点:
A:构造方法
抽象类有构造方法,但是本身不能被实例化。
它的构造方法用于子类实例化使用。
B:成员变量
抽象类既可以有成员变量,也可以有成员常量。
C:成员方法
抽象类既可以抽象方法,也可以有非抽象方法。
代码示例:
abstract class Animal
{
private String name;
public final int x = 10;
public Animal()
{
System.out.println("animal");
}
public Animal(String name)
{
this.name = name;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void show()
{
System.out.println("今天天气不错,适合学习");
}
public abstract void method();//定义抽象方法
}
class Dog extends Animal
{
public Dog()
{
super();
System.out.println("dog");
}
public Dog(String name)
{
super(name);
}
public void show()
{
System.out.println("今天天气不错,适合郊游");
}
public void method()
{
System.out.println("dog method");
}
}
class AbstractDemo2
{
public static void main(String[] args)
{
//创建对象
//Animal a = new Animal();
Dog d = new Dog();
System.out.println(d.getName());
Dog d2 = new Dog("小白");
System.out.println(d2.getName());
d2.show();
d2.method();
}
}
(4)使用:
当一个类继承一个抽象类的时候
要么重写抽象类的所有抽象方法。
要么本身是一个抽象类。
(5)抽象类的注意事项
A:抽象类没有构造方法,那么有什么用?
有,用于子类实例化使用。
B:是否有非抽象方法?如果没有抽象方法类为什么要定义为抽象类?
有,提高代码复用性。
没有抽象方法的抽象类就是为了不让他能创建对象。
C:abstract不能和哪些关键系并存。
private:私有的功能,子类是不能重写的。而abstract是要求子类重写的。
fianl:最终的意思,子类不能重写。而abstract是要求子类重写的。
static:静态的意思,它是跟类相关的。而我们研究的是对象间的关系。
静态的东西,可以通过类名调用,但是,抽象的方法,用类名调用没有实际意义。
修饰关键字:
默认修饰符,private,public -- 成员变量private,成员方法public
fianl:最终的,可以修饰类,成员变量,成员方法
static:让成员多了一种调用方式。可以修饰成员。
abstract:修饰类,修饰方法,表示是抽象。
组合使用:
一般格式:
权限修饰符+static+final+成员变量/方法
代码示例:
/*
老师示例
具体事物:基础班老师,就业班老师
共性:姓名,年龄,讲课。
根据我们学过的面向对象知识,我们就可以如下分析:
定义一个老师类,然后,分别让基础班老师和就业班老师继承老师类。
如何定义一个老师类呢,就是分析基础班老师和就业班老师的共性内容:
老师类:
成员变量:姓名,年龄
成员方法:讲课 因为每个老师讲课的内容不一样,所以,我们定义为抽象方法。
基础班老师:
重写讲课方法
输出老师的信息。
就业班老师:
重写讲课方法
输出老师的信息。
*/
abstract class Teacher
{
private String name;
private int age;
public Teacher(){}
public Teacher(String name,int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
//抽象的讲课方法
public abstract void teach();
public void printMessage()
{
System.out.println(name+"***"+age);
}
}
class BaseTeacher extends Teacher
{
public BaseTeacher(String name,int age)
{
super(name,age);
}
public void teach()
{
System.out.println("基础班老师讲JavaSE");
}
/*
public void printMessage()
{
System.out.println(getName()+"***"+getAge());
}
*/
}
class WorkTeacher extends Teacher
{
public WorkTeacher(String name,int age)
{
super(name,age);
}
public void teach()
{
System.out.println("就业班老师讲JavaEE");
}
}
class TeacherDemo
{
public static void main(String[] args)
{
BaseTeacher bt = new BaseTeacher("林青霞",25);
bt.teach();
bt.printMessage();
WorkTeacher wt = new WorkTeacher("郭德纲",38);
wt.teach();
wt.printMessage();
//使用多态
Teacher t = new BaseTeacher("刘姐",18);
t.teach();
t.printMessage();
t = new WorkTeacher("芙蓉姐姐",20);
t.teach();
t.printMessage();
}
}
二、接口
(1)接口:当一个抽象类中的方法都是抽象的时候,(并且都是成员常量的时候的。)java提供了一个新的表示形式,那就是接口。
(2)好处:
A:接口是对外暴露的规则(比如:USB,电脑内部的插槽,CPU的针孔)
B:接口是功能的扩展
C:接口降低了程序的耦合性
低耦合:类与类之间的关系
高内聚:类本身的能力
D:接口可以用来多实现
E:类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口
F:接口与接口之间可以有继承关系
(3)成员特点:
A:成员变量
成员变量都是常量,因为有默认修饰符:public static final
B:成员方法
成员方法都是抽象的,因为有默认修饰符:public abstract
建议,每次自己写接口的时候,尽量把修饰符自己写上。
(4)类,接口相互间的关系:
A:类与类
继承关系,java只支持类的单继承,但是可以多重(层)继承。
B:类与接口
实现关系,可以单实现,也可以多实现。
还可以在继承一个类的同时,实现多个接口。
C:接口与接口
继承关系,可以单继承,也可以多继承。
如果一个类实现一个接口,就必须实现该接口及其父接口的所有抽象方法。
代码示例:
interface Inter//定义一个接口
{
public abstract void show();//方法是抽象的
}
interface Inter2//定义第二个接口,两个方法都是抽象的
{
public abstract void method();
public abstract void show();
}
interface Inter3 extends Inter,Inter2//第三个接口继承了前两个接口
{
public abstract void function();
}
class Fu //默认有个extends Object
{
}
class Demo extends Fu implements Inter,Inter2//继承Fu类并实现了前两个接口
{
public void show()//复写show方法
{
System.out.println("demo show");
}
public void method()//复写method方法
{
System.out.println("demo method");
}
}
三、抽象类和接口的区别:
(A)成员区别:
抽象类:
构造方法
成员变量:可以是变量,也可以是常量。
成员方法:可以是抽象方法,也可以是非抽象方法。
接口:
成员变量:只能是常量。默认修饰符:public static final
成员方法:只能是抽象方法。默认修饰符:public abstract
(2)类只能单继承
而接口可以多继承。接口的出现避免了java的单继承的局限性。
(3)抽象类被继承,类中定义的是继承体系的共性内容。
接口被实现,接口中定义的是体系的扩展内容。
(4)设计理解不同:
抽象类被继承,体现的是一种:"is a" 的关系
接口被实现,体现的是一种:"like a" 的关系
代码示例:
abstract class Person//抽象类
{
private String name;
private int age;
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setAge(int age)
{
this.age = age;
}
public int getAge()
{
return age;
}
public abstract void eat();//定义抽象方法
}
abstract class Player extends Person
{
public abstract void study();//抽象方法
}
abstract class Coach extends Person
{
public abstract void teach();//抽象方法
}
interface StudyEnglish//接口
{
public abstract void studyEnglish();//接口中的抽象方法
}
class PingPongStu extends Player implements StudyEnglish
{
public void studyEnglish()//复写抽象方法
{
System.out.println("乒乓运动员学英语");
}
public void study()//复写抽象方法
{
System.out.println("乒乓运动员学习乒乓");
}
public void eat()//复写抽象方法
{
System.out.println("乒乓运动员吃乒乓");
}
}
class PingPongCoach extends Coach implements StudyEnglish
{
public void studyEnglish()//复写抽象方法
{
System.out.println("乒乓教练学英语");
}
public void teach()//复写抽象方法
{
System.out.println("乒乓教练教学员学乒乓");
}
public void eat()//复写抽象方法
{
System.out.println("乒乓教练吃乒乓乒乓");
}
}
class BasketStu extends Player
{
public void study()//复写抽象方法
{
System.out.println("篮球运动员学打篮球");
}
public void eat()//复写抽象方法
{
System.out.println("篮球运动员吃篮球");
}
}
class BasketCoach extends Coach
{
public void teach()//复写抽象方法
{
System.out.println("篮球教练教学员学打篮球");
}
public void eat()//复写抽象方法
{
System.out.println("篮球教练吃篮球");
}
}
class PersonDemo
{
public static void main(String[] args)
{
PingPongStu pps = new PingPongStu();
pps.setName("王浩");
pps.setAge(44);
System.out.println("姓名是:"+pps.getName()+",年龄是:"+pps.getAge());
pps.study();
pps.eat();
pps.studyEnglish();
System.out.println("************************");
BasketStu bs = new BasketStu();
bs.setName("姚明");
bs.setAge(50);
System.out.println("姓名是:"+bs.getName()+",年龄是:"+bs.getAge());
bs.study();
bs.eat();
System.out.println("************************");
PingPongCoach ppc = new PingPongCoach();
ppc.setName("乒乓刘教练");
ppc.setAge(36);
System.out.println("姓名是:"+ppc.getName()+",年龄是:"+ppc.getAge());
ppc.teach();
ppc.eat();
ppc.studyEnglish();
System.out.println("************************");
BasketCoach bc = new BasketCoach();
bc.setName("篮球张教练");
bc.setAge(25);
System.out.println("姓名是:"+bc.getName()+",年龄是:"+bc.getAge());
bc.teach();
bc.eat();
}
}
四、Object类的使用
Object:类Object是类层次结构的根类。每个类都使用Object作为超类。
Object类中我们要掌握的功能:
A:public String toString()
返回该对象的字符串表示。建议所有子类都重写此方法。
如果没有重写,默认的结果是:
getClass().getName() + '@' + Integer.toHexString(hashCode())
类名@哈希值的十六进制
public static String toHexString(int i):把i按照十六进制的数据返回。
为什么要重写呢?
因为地址值的显示对我们来说,没有意义。
为了让显示的效果有意义一些,重写此方法。
代码示例:
class Student extends Object
{
private String name;
public Student(){}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
//重写方法
public String toString()
{
//成员变量的组成:多个成员变量用,隔开。
//"name:"+name+",age:"+age;
return "name:"+name;
}
}
class ObjectDemo
{
public static void main(String[] args)
{
//创建对象
Student s = new Student();
s.setName("林青霞");
//Student@3e0ebb
//其实在用输出语句输出一个对象的名称的时候,其实是用对象调用了toString()方法而已。
System.out.println(s);
System.out.println(s.toString()); //类@十六进制的hashCode()
//hashCode方法
System.out.println(s.hashCode()); //4067003 -- int
System.out.println(Integer.toHexString(4067003)); //3e0ebb
}
}
B:public int hashCode()
返回该对象的哈希码值。
C:finalize()
当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
D:Class getClass():反射的时候讲。
返回的是该类的字节码文件对象的类文件。
E:public boolean equals(Object obj)
指示其他某个对象是否与此对象"相等"。
如果类没有重写equals方法,那么它比的还是地址值。
代码示例:
class Student
{
private String name;
private int age;
public Student(){}
public Student(String name,int age)
{
this.name = name;
this.age = age;
}
//重写equals方法
public boolean equals(Object obj)//重写的是Object类中的equals方法
{
//为了提高程序的效率
if(this == obj)
{
return true;
}
//为了提高程序健壮性
if(!(obj instanceof Student))
{
return false;
}
Student s = (Student)obj; //向下转型
//这个if语句可以使用三元运算符改进
//下边equals是String类中重写Object类中equals之后的
return this.name.equals(s.name) && this.age == s.age;
}
}
class Demo
{
}
class ObjectDemo3
{
public static void main(String[] args)
{
Student s1 = new Student("李建峰",18);
Student s2 = new Student("李建峰",18);
Student s3 = new Student("张学友",20);
System.out.println(s1.equals(s2));
System.out.println(s1.equals(s3));
//自己跟自己比
System.out.println(s1.equals(s1));
Demo d = new Demo();
//ClassCastException
System.out.println(s1.equals(d));
}
}
五、内部类
1、内部类定义:
将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类,嵌套类)。
2、访问特点:
A:内部类可以直接访问外部类中的成员,包括私有成员
B:外部类要访问内部类中的成员必须要建立内部类的对象
代码示例:
class Outer
{
private int num = 10;
//成员内部类
class Inner
{
public void show()
{
System.out.println("num:"+num);
}
}
//成员方法
public void method()
{
//创建对象
Inner in = new Inner();
in.show();
}
}
class InnerDemo
{
public static void main(String[] args)
{
//在外部使用
Outer o = new Outer();
o.method();
//注意格式:外部类.内部类 名字 = 外部类对象.内部类对象
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
3、内部类位置
A:成员位置
a:如果没有被private或者static修饰。
外部类.内部类 名字 = 外部类对象.内部类对象;
举例:
Outer.Inner oi = new Outer().new Inner();
oi.show();
b:被private或者static修饰。
如果被private修饰后,就不能再在除了外部类的其他类中使用。
如果被static修饰,并且没有被private修饰,使用方式如下:
外部类.内部类 名字 = 外部类.内部类对象;
举例:
Outer.Inner oi = new Outer.Inner();
oi.show();
代码示例:
/*
内部类被静态修饰:
*/
class Outer
{
private static int num = 10;
static class Inner
{
public void show()
{
System.out.println("show:"+num);
}
public static void method()
{
System.out.println("method:"+num);
}
}
}
class InnerDemo3
{
public static void main(String[] args)
{
//Outer.Inner oi = new Outer().new Inner();
Outer.Inner oi = new Outer.Inner();
oi.show();
oi.method();
//静态的不想通过对象访问
Outer.Inner.method();
}
}
内部类被private修饰:
/*
内部类被private修饰
*/
class Outer
{
private int num = 10;
private class Inner
{
public void show()
{
System.out.println("num:"+num);
}
}
public void method()
{
Inner in = new Inner();
in.show();
}
}
class InnerDemo2
{
public static void main(String[] args)
{
//内部类被private修饰后就不能再被使用
//Outer.Inner oi = new Outer().new Inner();
Outer o = new Outer();
o.method();
}
}
B:局部位置
a:有名字
按照普通的方式使用即可。
b:没有名字,匿名内部类(掌握)
格式:
new 类或者接口()
{
重写方法,或者自定义方法
};
其实这里的本质是一个子类匿名对象。
前提:外部存在着一个类或者接口。
内部类定义在局部位置:
在外部类的方法中定义一个类。
为什么局部内部类访问局部变量需要用final修饰呢?
因为内部类在使用完毕后,可能在堆内存还存在呢,这个时候,它要的变量也要存在。
如果没用final修饰,变量就会从栈中消失。
final修饰的内容在哪里?
方法区里面有一个常量区。它的生命周期你可以想象成和static一样。
代码示例:
class Outer
{
//private int num = 10;
public void method()
{
final int num = 20;
//局部位置
class Inner
{
public void show()
{
System.out.println("show "+num);
}
}
//创建对象
Inner in = new Inner();
in.show();
}
}
class InnerDemo4
{
public static void main(String[] args)
{
Outer o = new Outer();
o.method();
}
}
什么时候使用匿名内部类呢?
通常在使用方法是接口类型参数,并该接口中的方法不超过三个时,可以将匿名内部类作为参数传递。
增强阅读性。
匿名内部类的使用:
interface Inter
{
public abstract void hello();
public abstract void haha();
}
class Outer
{
private int num = 10;
public void method()
{
/*
class Inner//内部类形式
{
public void show()
{
System.out.println("num:"+num);
}
}
Inner in = new Inner();
in.show();
*/
/*
new Inter(){//匿名内部类
public void hello()
{
System.out.println("hello");
}
};
*/
//怎么调用呢?
/*
new Inter(){//匿名内部类调用方法
public void hello()
{
System.out.println("hello");
}
}.hello();
*/
/*
new Inter(){
public void hello()
{
System.out.println("hello");
}
public void haha()
{
System.out.println("haha");
}
}.hello();
new Inter(){
public void hello()
{
System.out.println("hello");
}
public void haha()
{
System.out.println("haha");
}
}.haha();
*/
//假如只是实现了接口的方法,那么还可以这样用
Inter in = new Inter(){
public void hello()
{
System.out.println("hello");
}
public void haha()
{
System.out.println("haha");
}
};
in.hello();
in.haha();
}
}
class NiMingInnerDemo
{
public static void main(String[] args)
{
Outer o = new Outer();
o.method();
}
}