面向对象(中)
this关键字
①通过this关键字可以明确地去访问一个类的成员变量,解决与局部变量名称冲突问题。
②构造方法是在实例化对象时被Java虚拟机自动调用的,在程序中不能像调用其他方法一样去调用构造方法,但可以在一个构造方法中使用“this([ 参数1,参数2…… ])”的形式来调用其他的构造方法
运行结果在使用this调用类的构造方法时。应注意以下几点。
1)只能在构造方法中使用this调用其他的构造方法,不能在成员方法中使用
2)在构造方法中,使用this调用构造方法的语句必须位于第一位,且只能出现一次
3)不能在一个类的两个构造方法中使用this互相调用
垃圾回收(System.gc ( ) 方法)
在Java中,当一个对象成为垃圾对象后仍会占用内存空间,时间一长,就会导致内存空间的不足。针对这种情况,java中引用了垃圾回收机制。有了这种机制,程序员不需要过多关心垃圾对象回收的问题,Java虚拟机会自动回收垃圾对象所占用的内存空间。
一个对象在成为垃圾后会暂时地保留在内存中,当这样的垃圾堆积到一定程度时,Java虚拟机就会启动垃圾回收器将这些垃圾对象从内存中释放,从而使程序获得更多的内存空间。除了等待Java虚拟机进行自动回收外,还可以通过调用System.gc ( ) 方法来通知Java虚拟机立即进行垃圾回收。当一个对象在内存中被释放时,它的finalize ( ) 方法会被自动调用,因此在类中通过定义finalize ( ) 方法来观察对象何时被释放。
注意:Sysytem.gc()只是通知JVM进行垃圾回收,但JVM具体什么时候回收是程序员无法控制的。
什么时候回收JVM有自己的想法,我个人认为这个方法没啥用。
static关键字
用于修饰类的成员,如成员变量、成员方法以及代码块等,被static修饰的成员具备一些特殊的属性。
静态变量
在定义一个类时,只是在描述某类事物的特征和行为,并没有产生具体的数据。只有通过new关键字创建该类的实例对象后,系统才会为每个对象分配空间,储存各自的数据。有时候,开发人员会希望某些特定的数据在内存中只有一份,而且能够被一个类的所有实例所共享。就可以使用static关键字来修饰成员变量,该变量被称作静态变量。静态变量被所有实例共享,可以使用“类名.变量名”的形式来访问。
注意:static关键字只能用于修饰成员变量,不能用于修饰局部变量,否则编译会报错。
静态方法
在实际开发时,开发人员有时会希望在不创建对象的情况下就可以调用某个方法,换句话说也就是使该方法不必和对象绑在一起。要实现这样的效果,只需要在类中定义的方法前面加上static关键字即可,通常称这种方法为静态方法。同静态变量一样,静态方法可以使用“类名.方法名”的方式来访问,也可以通过类的实例对象来访问。
打印了两次注意:在一个静态方法中只能访问用static修饰的方法,原因在于没有被static修饰的成员需要先创建对象才能访问,而静态方法在被调用时可以不创建任何对象。
静态代码块
在Java中,使用一对大括号围起来的若干行代码被称为代码块,用static关键字修饰的代码块称为静态代码块。当类被加载时,静态代码块会执行,由于类只加载一次,因此静态代码块只执行一次。在程序中,经常使用静态代码块来对类的成员变量进行初始化。
实例化两次,静态代码块只执行了一次说明静态代码块在类第一次使用时才会被加载,并且只会加载一次。
成员内部类
在Java中,允许一个类的内部定义类,这样的类称作内部类。
这个内部类所在的类称作外部类。根据内部类的位置、修饰符和定义的方式可分为成员内部类、静态内部类、方法内部类。
在一个类中除了可以定义成员变量、成员方法外,还可以定义类,这样的类被称作成员内部类。
在成员内部类中,可以访问外部类的所有成员。
内部类可以在外部类中被使用,并能访问外部类的成员。
如果想通过外部类去访问内部类,则需要通过外部类对象去创建内部类对象,创建内部类对象的具体语法格式如下:
外部类名.内部类目 变量名 = new 外部类名( ) . new 内部类目( ) ;
如针对上面匿名内部类定义的Outer类写一个测试程序
通过外部类访问内部类需要注意的是,如果外部类被声明为私有,外界将无法访问。图中内部类Inner被private修饰,则上述编译将会被报错。
类的继承(extends关键字)
继承类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有类被已称作父类,子类会自动拥有父类所有可继承的属性和方法。在程序中,入过想声明一个类继承另一个类,需要使用extents关键字。
继承 运行结果Dog类通过关键字extends继承了Animal类,这样Dog类便是Animal类的两个子类。虽然子类没有定义name属性和shout()方法,但是却能访问这两个成员。这就说明子类在继承父类的时候,会自动拥有父类所有的成员。
在类的继承中,需要注意一些问题,具体如下。
1)在java中,类只支持单继承,不允许多重继承,也就是说一个类只能有一个直接父类,例如下面这种是不合法的
class A{ }
class B{ }
class C extends A,B{ } //C类不能同时继承A类和B类
2)多个类可以继承一个父类,例如下面这种情况是允许的
class A{ }
class B{ } extends A{ }
class C{ } extends A{ } //类B和类B都可以继承类A
3)在java中,多重继承是允许的,即一个类的父类可以再去继承另外的父类,例如C类继承自B类,而B类又可以去继承A类,这时,C类也可称作A类的子类。例如下面这种情况
class A{ }
class B{ } extends A{ } //类B继承类A,类B是类A的子类
class C{ } extends B{ } //类C继承类B,类C是类B和类A的子类
4)在java中,子类和父类是一种相对概念,也就是说一个类是某个类父类的同时,也可以是另一个类的子类。例如上面的实例中,B类是A类的子类,同时又是C类的父类。
重写父类方法
在继承关系中,子类会自动继承父类中定义的方法,但有时在子类中需要对继承的方法进行一些修改,即对父类的方法进行重写。需要注意的是,在子类中重写的方法需要和父类被重写的方法具有相同的方法名、参数列表以及返回值类型。
重写父类方法 运行结果从结果可以看出,在调用Dog类对象的shout( ) 方法时,只会调用子类重写的该方法,并不会调用父类的shout( )方法。
注意:子类重写父类时,不能使用比父类中被重写的方法更严格的访问权限
super关键字
当子类重写父类的方法后,子类对象将无法访问父类被重写的方法。为了解决这个问题,Java中专门提供了一个super关键字用于访问父类的成员。例如访问父类的成员变量、成员方法和构造方法。
1)使用super关键字访问父类的成员变量和成员方法,具体格式如下。
super 运行结果super.成员变量
super.成员方法([ 参数1,参数2… ])
1)使用super关键字访问父类的构造方法,具体格式如下。
super访问父类构造方法 运行结果super([ 参数1,参数2… ])
注意:super调用父类构造方法的代码必须位于子类构造方法的第一行,并且只能出现一次。
如果将上图中super("沙皮狗")注释掉,编译会报出
Implicit super constructor Animal() is undefined. Must explicitly invoke another constructor,
的错误,这里出错的原因是在子类的构造方法中一定会调用父类的某个构造方法。这时可以在子类的构造方法中通过super指定调用父类的哪个构造方法,如果没有指定,在实例化子类对象时,会自动调用父类无参构造方法。而在代码中因为定义了有参的构造方法,而没有定义有参的构造方法,所以报错。为了解决上述问题,可以在子类中调用父类已有的构造方法,也可以选择在父类中定义无参的构造方法来解决。
所以得出一个结论:在定义一个类的时候,如果没有特殊要求,尽量在类中定义一个无参的构造方法,避免被继承时出现错误