本章承接Java编程基础-面向对象(上)一文。
一、static关键字
在java中,定义了一个static关键字,它用于修饰类的成员,如成员变量、成员方法以及代码块等,被static修饰的成员具备一些特性。
1、static关键字的特点:
a)随着类的加载而加载,也就是说,静态会随着类的消失而消失,说明它的生命周期最长。
b)优先于对象存在,明确一点,静态是先存在的,对象是后存在的。
c)被类的所有对象共享。
d)可以通过类名调用。
2、静态变量
在一个java类中,可以使用static关键字来修饰成员变量,该变量被称作静态变量。静态变量被所有实例共享,可以使用”类名.变量名”的形式来访问。
代码示例:
[java] view plain copy
- public class Student {
- static String schoolName;//定义静态变量schoolName
- }
- public class TestStudent {
- public static void main(String[] args) {
- Student stu1=new Student();//创建学生对象
- Student stu2=new Student();
- Student.schoolName="北京科技大学";//为静态变量赋值
- System.out.println("我的学校是"+stu1.schoolName);
- System.out.println("我的学校是"+stu2.schoolName);
- }
- }
注意:static关键字只能用于修饰成员变量,不能用于修饰局部变量,否则编译会报错。
什么时候定义静态变量(类变量)呢?
当对象中出现共享数据时,该数据被静态所修饰,对象中特有的数据要定义成非静态存储于堆内存中。
3、静态方法
概念:不创建对象的情况下就可以调用某个方法,换句话说,也就是使该方法不必和对象绑在一起。只需在类中定义的方法前加上static关键字即可。同静态变量一样,静态方法可以使用”类名.方法名”的方式来访问,也可以通过类的实例对象来访问。
注意:在一个静态方法中只能访问用static修饰的成员,原因在于没有被static修饰的成员需要先创建对象才能访问,而静态方法在被调用时可以不创建任何对象。
什么时候定义静态函数?
当功能内部没有访问到非静态数据(对象的特有数据),那么该功能可以定义成静态的。
静态的使用注意事项:
a)静态方法只能访问静态成员(包括方法和变量),非静态方法既可以访问静态也可以访问非静态。
b)静态方法中不可以定义this,super关键字。因为静态优先于对象存在,所以静态方法中不可以出现this。
c)主函数是静态的。
静态利弊:
利处:对对象的共享数据进行单独空间的存储,节省空间,没有必要每一个对象中都存储一份。可以直接被类名调用。
弊端:生命周期过长,访问出现局限性。
4、静态代码块
- class StaticCode {
- int num = 9;
- StaticCode() {
- System.out.println("b");
- }
- static // 静态代码块
- {
- System.out.println("a");
- }
- // 构造代码块
- {
- System.out.println("c" + this.num);
- }
- StaticCode(int x) {// 构造函数
- System.out.println("d");
- }
- public static void show() {
- System.out.println("show run");
- }
- }
- public class StaticCodeDemo {
- public static void main(String[] args) {
- new StaticCode(4);
- }
- }
运行结果为:
a
c9
d
二、内部类
1、概念:内部类顾名思义是指在一个类的内部再定义一个类。
注意:内部类是个编译时的概念,一旦编译成功后,它就与外部类属于两个完全不同的类(当然他们之间还是有联系的)。对于一个名为OuterClass的外部类和一个名为InnerClass的内部类,在编译成功后,会出现这样两个class文件:OuterClass.class和OuterClass$InnerClass.class。
2、分类:
java内部类主要分为四种:成员内部类、局部内部类、静态内部类和匿名内部类。
a)成员内部类:成员内部类是最普通的内部类,在成员内部类中可以访问外部类的所有成员,包括私有。之所以可以访问,是因为内部类中持有了一个外部类的引用,外部类名.this.外部类要访问内部类的所有成员,必须要创建内部类对象。
注意:成员内部类中不能存在任何用static修饰的变量和方法;成员内部类是依附于外部类的,所以只有先创建了外部类才能够创建内部类。
创建内部类对象的具体语法格式:外部类类型.内部类类型 变量名=new 外部类名().new 内部类名();
[java] view plain copy
- public class OuterClass {// 外部类
- private String str;// 外部类中的属性
- public void outerDisplay() {// 外部类中的方法
- System.out.println("outerClass...");
- }
- public class InnerClass {// 内部类
- public void innerDisplay() {// 内部类中的方法
- // 使用外部类的属性
- str = "abcd";
- System.out.println(str);
- // 调用外部类中的方法
- outerDisplay();
- }
- }
- /* 推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 */
- public InnerClass getInnerClass() {
- return new InnerClass();
- }
- public static void main(String[] args) {
- OuterClass outer = new OuterClass();
- OuterClass.InnerClass inner = outer.getInnerClass();
- inner.innerDisplay();
- }
- }
b)局部内部类:它嵌套在方法和作用域内,它只能在该方法和属性中被使用,出了方法和作用域就会失效。
定义在方法中:
[java] view plain copy
- public class Parcel5 {
- public Destionation destionation(String str){
- class PDestionation implements Destionation{
- private String label;
- private PDestionation(String whereTo){
- label = whereTo;
- }
- public String readLabel(){
- return label;
- }
- }
- return new PDestionation(str);
- }
- public static void main(String[] args) {
- Parcel5 parcel5 = new Parcel5();
- Destionation d = parcel5.destionation("chenssy");
- }
- }
定义在作用域内:
[java] view plain copy
- public class Parcel6 {
- private void internalTracking(boolean b){
- if(b){
- class TrackingSlip{
- private String id;
- TrackingSlip(String s) {
- id = s;
- }
- String getSlip(){
- return id;
- }
- }
- TrackingSlip ts = new TrackingSlip("chenssy");
- String string = ts.getSlip();
- }
- }
- public void track(){
- internalTracking(true);
- }
- public static void main(String[] args) {
- Parcel6 parcel6 = new Parcel6();
- parcel6.track();
- }
- }
c)静态内部类:可以使用static关键字来修饰一个成员内部类,该内部类被称作静态内部类,它可以在不创建外部类对象的情况下被实例化。
注意:在静态内部类中只能访问外部类的静态成员。在静态内部类中可以定义静态成员,而在非静态的内部类中不允许定义静态的成员。
d)匿名内部类:在做swing编程时,我们常用匿名内部类的方式来绑定事件。
注意几点:
a)匿名内部类是没有访问修饰符的。
b)new 匿名内部类,这个类首先是要存在的。
c)当所在方法的形参需要被匿名内部类使用,那么这个形参就必须为final。
d) 匿名内部类是没有构造方法的。因为它连名字都没有何来构造方法。
三、匿名对象
1、匿名对象:没有名字的实体,也就是该实体没有对应的变量名引用。
2、匿名对象的用途:
当对象对方法进行一次调用的时候,可以使用匿名对象对代码进行简化。调用完之后,该对象不再使用,并被回收。为什么只对方法,而不调用属性呢?因为匿名对象调用属性没意义。如果对象要多成员进行多次调用,必须给对象起个名字。不能在使用匿名对象。匿名对象可以实际参数进行传递。
3、匿名对象的简单演示
new 类名().方法名();
注意:
a)匿名对象设置的属性永远无法获取? 没有引用变量指向那个对象。
b)任何两个匿名对象使用==比较,永远返回false。
c)匿名对象主要应用于实参。
四、类的继承
1、继承概念:在程序中,继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关系体系。在java中,类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有的类被称作父类,子类会自动拥有父类所有可继承的属性和方法。在程序中,如果想声明一个类继承另一个类,需要使用extends关键字。
格式: class 子类名 extends 父类名{}
继承的好处:提高了代码的复用性,提高了代码的维护性,让类与类之间产生了关系,是多态的前提。
在类的继承中,需要注意的问题:
a)在java中,类只支持单继承,不允许多重继承,也就是说一个类只能有一个直接父类。因为多继承容易带来安全隐患:当多个父类中定义了相同功能,当功能内容不同时,子类对象不确定要运行哪一个。例如:C类不能同时继承A类和B类。
b)多个类可以继承一个父类。
c)在java中,多层继承是可以的,即一个类的父类可以再去继承另外的父类,例如:C类继承自B类,而B类又可以去继承自A类,这时,C类也可以称作A类的子类。
代码示例:
[java] view plain copy
- class Animal {
- String name;
- public void shout() {
- System.out.println("动物发出叫声");
- }
- }
- class Cat extends Animal {
- public void catchFish() {
- System.out.println("猫在抓鱼");
- }
- }
- public class Demo {
- public static void main(String[] args) {
- Cat c = new Cat();
- c.shout();//调用父类的shout()方法
- }
- }
注意:子类只能继承父类所有非私有的成员(成员方法与成员变量);不能继承父类的构造方法,但可以通过super关键字来访问父类的构造方法;不要为了部分功能而去继承。
2、重写父类方法:
在继承关系中,子类会自动继承父类中定义的方法,但有时在子类中需要对继承的方法进行一些修改,即对父类的方法进行重写。需要注意的是,在子类中重写的方法需要和父类被重写的方法具有相同的方法名、参数列表和返回值类型。(也称方法覆盖,方法复写)
代码示例:
[java] view plain copy
- class Animal {
- String name;
- public void shout() {
- System.out.println("动物发出叫声");
- }
- }
- class Cat extends Animal {
- public void shout() {//重写父类的shout()方法
- System.out.println("猫咪发出叫声");
- }
- }
- public class Demo {
- public static void main(String[] args) {
- Cat c = new Cat();
- c.shout();
- }
- }
方法重写时要遵循的规则:
“三同一小一大”规则
“三同”即方法名相同,形参列表相同、返回值类型相同;
“一小”子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等;
“一大”指的子类方法的访问权限应比父类方法更大或相等;
覆盖方法和被覆盖方法要么都是类方法,要么都是实例方法,不能一个是类方法,一个是实例方法。
注意:
a) 子类重写父类方法时,不能使用比父类中被重写的方法更严格的访问权限。
b) 父类中的私有方法不能被重写,父类私有,子类根本无法继承。
c) 父类静态方法,子类也必须通过静态方法重写。
d) 子类重写父类方法的时候,最好声明的一模一样。
3、重写和重载的区别:
a) 方法的重写:要有继承关系,是在子父类方法中声明相同(方法名和参数列表都相同)。与返回值类型有关,覆盖时,子类方法的访问权限不能小于父类方法的访问权限,静态只能覆盖静态。
b) 方法的重载:在同一个类中,方法名相同,参数列表不同,与返回值类型无关。
五、super关键字
当子类重写父类方法后,子类对象将无法访问父类被重写的方法,为了解决这个问题,在java中专门提供了一个super关键字用于访问父类的成员。例如:访问父类的成员变量、成员方法和构造方法。
1、 使用super关键字调用父类的成员变量和成员方法。
具体格式:
super.成员变量
super.成员方法({参数1},{参数2..})
代码示例:
[java] view plain copy
- class Animal // 定义Animal类
- {
- String name = "动物";
- void shout()// 定义动物叫的方法
- {
- System.out.println("动物发出叫声");
- }
- }
- class Dog extends Animal// 定义Dog类继承Animal类
- {
- String name = "犬类";
- void shout() {
- super.shout();// 访问父类的成员方法
- }
- void printName() {
- System.out.println("name=" + super.name);// 访问父类的成员变量
- }
- }
- class Demo {
- public static void main(String[] args) {
- Dog dog = new Dog();// 创建Dog的实例对象
- dog.shout();// 调用dog重写shout()方法
- dog.printName();// 调用dog对象的printName()方法
- }
- }
2、
使用super关键字调用父类的构造方法。
super.([参数1],[参数2..])通过super调用父类的构造方法代码必须位于子类构造方法的第一行并且只能出现一次。
代码示例:
[java] view plain copy
- class Animal // 定义Animal类
- {
- String name;
- public Animal(String name)// 定义Animal类的构造方法
- {
- this.name = name;
- }
- }
- class Dog extends Animal// 定义Dog类继承Animal类
- {
- public Dog() {
- super("柴犬");// 调用父类有参的构造方法
- }
- public void show() {
- System.out.println("我是一只" + name);
- }
- }
- class Demo {
- public static void main(String[] args) {
- Dog dog = new Dog();// 创建Dog的实例对象
- dog.show();
- }
- }
3、this和super的区别:
a) 调用成员变量:this调用本类的成员变量,super调用父类的成员变量。
b) 调用构造方法:this()调用本类的构造方法,super()调用父类的构造方法。
c) 调用成员方法:this调用本类的成员方法,super调用父类的成员方法。
d) 构造函数没有覆盖,this和super不能同时存在。
六、final关键字
final关键字可以用于修饰类、变量和方法。它有“这是无法改变的”或者“最终”的含义,因此被final修饰的类、变量和方法具有以下特性:
a)final修饰的类不能被继承。也就是不能够派生子类,为最终类。
b)final修饰的方法不能被子类重写。被final修饰的方法为最终方法。
c)final修饰的变量(成员变量和局部变量)是常量(自定义常量),只能赋值一次。当在描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这些值起个名字,方便阅读。而这个值不需要改变,所以加上final修饰。作为常量:常量的书写规范所有字母都大写,如果由多个单词组成,单词间通过下划线连接。