7.29学习总结
抽象类和接口
抽象类
1、关键词:abstract修饰,抽象类省略了要执行的一种或多种特定行为的细节。
2、抽象类的特点:
①包含抽象方法的类必为抽象类(非抽象类中不能包含抽象的方法);
而抽象类中并不一定非得包含抽象方法,也可以包含具体的方法。
上述代码反映了抽象类中不一定非得包含抽象方法,也可以包含具体方法。
②抽象类不能被实例化,但仍应定义它的构造方法,这种构造方法将在它子类的构造方法中被调用。而且,抽象类也可以用作数据类型。
如上图的代码中,Shape类是一个抽象类,但可以定义抽象类数据类型,第七行就是创建抽象类型的数组。
③所有的抽象方法都不能用private修饰。
④父类是具体的,其子类也可以为抽象的。
3、抽象类和普通类的区别:
抽象类不可以被实例化,即不能通过new来创建对象;如果抽象类的子类不再为抽象类时,抽象类可以通过子类来实例化。而普通类可以被实例化。
如上图方框中,Shape为抽象了,不能通过 new Shape()来实例化,但可以通过非抽象子类Circle来实例化。
4、抽象方法与普通方法的区别:
①普通方法必须要有方法体(至少包含一对大括号),抽象方法不能有方法体(大括号也没有)
②抽象方法要用abstract修饰,访问修饰符不能用private(因为子类中,必须继承父类中所有的方法,如果抽象方法被private修饰,则不能被子类继承。)
③抽象方法只能存在于抽象类/接口中
5、实例:
抽象类Shape:
public abstract class Shape {
public abstract double getArea();
public abstract void displayGeometricObject();
public boolean equalArea(Shape s){
boolean flag=false;
if(s.getArea()<this.getArea()){
flag=true;
}else{
flag=false;
}
return flag;
}
}
子类Circle:
public class Circle extends Shape{
private double r;
public Circle(double r){
this.r=r;
@Override
public double getArea() {//求圆的面积
// TODO Auto-generated method stub
return Math.PI*r*r;
}
@Override
public void displayGeometricObject() {//展示圆的信息
// TODO Auto-generated method stub
System.out.println("该圆的半径为:"+r);
System.out.println("其周长为:"+(2*Math.PI*r));
System.out.println("其面积为:"+(Math.PI*r*r));
}
}
子类Reactangle:
public class Reactangle extends Shape{
private double w;
private double h;
public Reactangle(double w,double h){
this.w=w;
this.h=h;
}
public double getArea() {//求矩形的面积
// TODO Auto-generated method stub
return w*h;
}
public void displayGeometricObject() {//展示矩形的信息
// TODO Auto-generated method stub
System.out.println("该矩形的长为:"+w);
System.out.println("宽为:"+h);
System.out.println("周长为:"+(2*(h+w)));
System.out.println("面积为:"+(h*w));
}
}
主类GeometricObject :
public class GeometricObject {
public static void main(String[] args) {
System.out.println("请输入圆的半径:");
Scanner s=new Scanner(System.in);
double r=s.nextDouble();
System.out.println("请输入矩形的长和宽:");
double w=s.nextDouble();
double h=s.nextDouble();
Shape c=new Circle(r);
Shape rt=new Reactangle(w,h);
c.displayGeometricObject();
rt.displayGeometricObject();
System.out.println(c.equalArea(rt));
}
}
运行结果:
请输入圆的半径:
2
请输入矩形的长和宽:
4
5
该圆的半径为:2.0
其周长为:12.566370614359172
其面积为:12.566370614359172
该矩形的长为:4.0
宽为:5.0
周长为:18.0
面积为:20.0
false
接口
1、概述:接口比抽象类更抽象,它仅仅声明了方法,只包含常量和抽象方法。
2、接口与抽象类的异同:
同:
抽象类和接口都不能通过new关键字类实例化;
都可以定义一个类型。
异:
①接口只抽象行为,
抽象类则要指定属性、具体的方法和抽象的方法;
②一个类可以继承自多个接口,但只能接成一个类,可以通过接口实现多重继承;
③接口中只包含常量和抽象方法;而抽象类中即可以包含常量和抽象方法,也可以包含变量和具体方法。
④在接口中,所有的数据域都是 public final static 的,所有的方法都是 public abstract 的。
3、问:为什么Java不支持多重继承?(补充)
答:因为当一个子类从两个以上的父类继承下来的时候,可能会出现属性和方法重复或冲突的现象。
原因分析:
多重继承发生问题原因之一在于属性(数据结构)冲突,也就是存储空间的冲突。由于接口不与任何存储空间相关联,因此可以解决存储空间冲突的问题。
对于继承的方法的冲突,当使用接口之后,由于接口只定义了方法的抽象,没有具体的执行代码,因此也不会发生代码冲突的问题。
4、拓展:
子类只有将接口中声明的所有方法,以及抽象类中所有的抽象方法都进行定义,这个子类才能成为一个“具体”的类,才能实例化。
如果你的基础类可以不带任何属性和方法定义时,可以将它定义成一个接口。只有在必须带有属性和方法定义的时候,才采用抽象类或具体类。
JAVA内部类
在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。
分类
成员内部类
1、概述:成员内部类是最普通的内部类,它的定义为位于另一个类的内部。
2、访问机制:
①成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。
②在外部类中,要想访问内部类,就不会那么简单了,外部类要想访问内部类,必须首先创建一个内部类的对象;而要创建成员内部类的对象,前提是必须存在一个外部类的引用,用于指向内部类对象。
外部类访问内部类的两种方式:
方式一:在main()方法中直接创建内部类对象和外部类引用。
public class Circle {
double r;
private int count = 1;//私有成员
static int count2 = 2;//static静态成员
public Circle(double r){
this.r=r;
}
public class Draw{
public void draw(){
System.out.println("drawshape,圆的半径为:"+r);
//内部类可以访问外部类所有成员,包括私有成员和静态成员
System.out.println("count="+count+",count2="+count2);
}
}
public static void main(String[] args) {
Circle c = new Circle(5);//创建外部类对象
Circle.Draw d = c.new Draw();//外部类引用指向内部类对象
d.draw();
}
}
运行结果:
drawshape,圆的半径为:5.0
count=1,count2=2
外部类:Circle,内部类:Draw。
在内部类Draw中访问外部类的私有成员count和静态成员count2。
如上述代码中main()方法中的语句:
Circle c = new Circle(5);先创建外部类的对象;
Circle.Draw d = c.new Draw();通过外部类的引用指向内部类的对象;
d.draw();最后通过内部类对象来访问内部类的方法。
方式二:将内部类对象的创建放在外部类的一个方法中,然后通过内部类的对象调用内部类的方法。代码如下:
public class Circle {
double r;
private int count = 1;//私有成员
static int count2 = 2;//static静态成员
public Circle(double r){
this.r=r;
getDrawInstance().draw();
//必须先创建成员内部类的对象,再进行访问
}
private Draw getDrawInstance() {//返回值为内部类类型的方法
return new Draw(); //方法实质上就是创建了内部类对象
}
public class Draw{//内部类
public void draw(){
System.out.println("drawshape,圆的半径为:"+r);
//内部类可以访问外部类所有成员,包括私有成员和静态成员
System.out.println("count="+count+""
+ ",count2="+count2);
}
}
public static void main(String[] args) {
Circle c = new Circle(5);
}
}
运行结果:
drawshape,圆的半径为:5.0
count=1,count2=2
在上述代码中,同样是通过创建内部类对象来访问内部类方法。只不过改程序将创建内部类的对象放在外部类的一个方法中,该方法的返回值为内部类类型的一个对象。通过该方法来访问内部类的方法。
局部内部类
1、概述:局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
2、实例:
public class Person {
String sex;
public Person(String sex){
this.sex = sex;
}
public Person getMen(){
Person sex = new Person("男");
return sex;
}
public Person getWomen(){
class Women extends Person{
public Women(String sex) {//成员内部类
super(sex);
// TODO Auto-generated constructor stub
}
}
return new Women(sex);
}
public static void main(String[] args) {
Person p = new Person("女");
//调用getWomen方法,访问局部内部类Women,返回Person类型对象
System.out.println(p.getWomen());
//调用getMen方法
System.out.println(p.getMen());
}
}
运行结果:
内部类.Person$1Women@15db9742
内部类.Person@6d06d69c
注意:当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量
外部类.this.成员方法
实例:
public class Outter {
public static void main(String[] args) {
Outter out = new Outter();
Outter.Inner inner = out.new Inner();
inner.a();
}
public static void a(){
System.out.println("这是外部类!");
}
class Inner{
void a() {//覆盖外部类中的方法
System.out.println("这是内部类!");
Outter.this.a();//内部类调用外部类中被覆盖的同名方法
}
}
}
运行结果:
这是内部类!
这是外部类!
匿名内部类
1、概述:在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护。匿名内部类也不能有访问修饰符和static修饰符。
如下列代码,就包含一个匿名内部类。
history_bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
2、特点:
①使用匿名内部类能够在实现父类或者接口中的方法情况下同时产生一个相应的对象;
②匿名内部类是唯一一种没有构造器的类,因此使用范围非常有限,大部分匿名内部类用于接口回调。
③匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。
3、实例:(监听器事件:匿名内部类)
外部监听器OnclickListener:
public interface OnclickListener {//外部监听器
public void onclick(Click e);
}
Click类:
public class Click {///事件
private String clicktype;
public Click(String clicktype) {
this.clicktype = clicktype;
}
public String getClicktype() {
return clicktype;
}
public void setClicktype(String clicktype) {
this.clicktype = clicktype;
}
}
按钮Button:
import java.util.Vector;
public class Button {
private Vector<OnclickListener> listeners = new Vector<OnclickListener>();
/**
* 添加监听器
* @param listener
*/
public void addListener(OnclickListener listener){
listeners.add(listener);
}
public void removeListener(OnclickListener listener){
listeners.remove(listener);
}
public void click(String cllicktype){
//发送消息
for(int i = 0; i < listeners.size(); i++){
listeners.get(i).onclick(new Click(cllicktype));
}
}
}
主类TestListener:
public class TestListener {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Button s = new Button();
MyListener l = new MyListener();
s.addListener(l);
s.click("点击");
s.addListener(new OnclickListener() {//匿名内部类
@Override
public void onclick(Click e) {
System.out.println("此次按键类型为:"+e.getClicktype());
}
});
s.click("长按");
s.removeListener(l);
s.click("轻触");
}
//静态内部类
static class MyListener implements OnclickListener{
@Override
public void onclick(Click e) {
System.out.println("click type is:" + e.getClicktype());
}
}
}
在TestListener类 中,包含一个静态内部类MyListener 和一个匿名内部类。匿名内部类为OnclickListener类的对象,用于实现onclick(Click e)方法。
该程序实现了按钮的监听事件。
运行结果如下:
运行结果:
click type is:点击
click type is:长按
此次按键类型为:长按
此次按键类型为:轻触
静态内部类
1、概述:成员内部类的一种特殊形式,成员内部类用static关键词修饰,即为静态内部类。
2、特点:
①静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似;
②静态内部类不能使用外部类的非static成员变量或者方法;
因为在没有外部类的对象的情况下,可以创建静态内部类的对象;
如果允许静态内部类访问外部类的非static成员,那就可以通过静态内部类的对象来访问外部类的非静态成员,就不需要外部类对象类调用,与“类中的非静态成员只能通过类的对象来访问”矛盾,所以静态内部类不能访问外部类的非静态成员。
3、实例:
public class Outter1 {
public static void main(String[] args) {
//静态内部类不依赖于外部类,可直接访问内部类
Inner inner = new Inner();
inner.b();
}
public static void a(){
System.out.println("这是外部类的静态方法!");
}
public void c(){
System.out.println("这是外部类的方法!");
}
static class Inner{
void b() {//覆盖外部类中的方法
System.out.println("这是内部类!");
a();
}
}
}
运行结果:
这是内部类!
这是外部类的静态方法!
静态内部类的可以访问外部类的静态成员,但不能访问外部类的非静态成员,如下图所示:
欠缺:
在今天的学习中,没有对内部类进行深入的了解。