面向对象编程(三)——继承
方法重写(方法覆盖)
- 子类中的方法名、参数的个数与类型和返回值和父类相同。即外壳不变,核心重写!
意义: 子类跟父类拥有同样的功能,但是子类有自己的特定内容和特定实现方式。为了见名知意,保持父类名字,自己重新实现方法体。
注意事项:- 不能重写声明为private或final或static方法
- 构造方法不能被重写
- 重写的时候,访问权限不能比父类中被重写的方法的访问权限更低。(最好保持权限一致)
- 重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。
重载(Overload)
- 重载(overloading) 是在一个类里面。方法名字相同,而参数的数量不同或数量相同而类型和次序不同,返回类型可以相同也可以不同的方法。
- 每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
- 最常用的地方就是构造器的重载。
注意事项:- 被重载的方法必须改变参数列表(参数个数或类型);
- 被重载的方法可以声明新的或更广的检查异常;
- 方法能够在同一个类中或者在一个子类中被重载。
重载(overload)和重写(override)的区别
区别点 | 重载 | 重写 |
---|---|---|
一般存在位置 | 同一个类中 | 子类与父类中 |
方法名 | 一样 | 一样 |
参数的个数与类型 | 不一样 | 一样 |
返回值类型 | 不要求 | 一样 |
异常 | 可以声明新的或更广的检查异常 | 可以减少或删除,不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常 |
总结
- 方法的重写(Overriding)和重载(Overloading)是java多态性的不同表现。
- 重写是父类与子类之间多态性的一种表现。
- 重载可以理解成多态的具体表现形式。
final(最终的、最后的)
可以修饰类、方法、变量
- final类
这个类不能被继承 - final方法
修饰一个方法:表示这个方法不能被子类重写 - final变量(变量分为成员变量和局部变量)
一般表示为自定义常量
Java 包(package)
Java 使用包(package)这种机制是为了防止命名冲突,访问控制,提供搜索和定位类(class)、接口、枚举(enumerations)和注释(annotation)等。
- 我们可以通过包对类进行分类管理,也可以避免重名问题。
- 把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。
- 同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。因此,包可以避免名字冲突。
- 包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。
怎么定义包
放在class前面
package xx.xx.xx;
带包的类的使用
- 第一种方式:直接在类前面加上包
xxx.xx.xxx x = new xxx.xxx.xx(); - 第二种方式:
import xxx.xxx.xx.xx;
import xx.xx.xx.*;
-
注意:
- 类文件中可以包含任意数量的 import 声明。import 声明必须在包声明之后,类声明之前。
带包的类的编译和运行
- 编译: javac -d . xx.java (编译的时候会根据你定义的包,创建对应的文件夹目录结构)
- 运行: java xxx.xxx.xx(带包名运行类)
-
注意:
-
- 编译之后的 .class 文件应该和 .java 源文件一样,它们放置的目录应该跟包的名字对应起来。
-
- 并不要求 .class 文件的路径跟相应的 .java 的路径一样。可以分开来安排源码和类的目录。这样,可以将类目录分享给其他的编程人员,而不用透露自己的源码。用这种方法管理源码和类文件可以让编译器和java 虚拟机(JVM)可以找到程序中使用的所有类型。
\sources\com\sise\test\Google.java
\classes\com\sise\test\Google.class//\classes 是 class path,package 名字是 com.sise.test。
而编译器和 JVM 会在 \classes\com\sise\test 中找 .class 文件。
- 并不要求 .class 文件的路径跟相应的 .java 的路径一样。可以分开来安排源码和类的目录。这样,可以将类目录分享给其他的编程人员,而不用透露自己的源码。用这种方法管理源码和类文件可以让编译器和java 虚拟机(JVM)可以找到程序中使用的所有类型。
-
- 类目录的绝对路径叫做 class path。设置在系统变量 CLASSPATH 中。编译器和 java 虚拟机通过将 package 名字加到 class path 后来构造 .class 文件的路径。
-
- 一个 class path 可能会包含好几个路径,多路径应该用分隔符分开。默认情况下,编译器和 JVM 查找当前目录。JAR 文件包含 Java 平台相关的类,所以他们的目录默认放在了 class path 中。
访问控制修饰符
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
- default (即缺省,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
- private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
- public : 对所有类可见。使用对象:类、接口、变量、方法
- protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
内部类与外部类
把一个类定义在另一个类的内部,这个被定义在内部的类称为内部类。包含内部类的叫做外部类。
- 内部类可以访问外部类的私有成员,外部类不能直接访问内部类的成员。
- 如果内部类是private的那只能在所在外部类内部使用
- 如果是public的话,那可以在所在外部类外部使用:外部类.内部类 对象名;
外部类
-
为什么类只有public和default两个访问权限?
- 因为类的作用域只有两个,包内和包外。public在包外也可以访问,default只能在包内访问。
在外部类外面创建内部类的对象:
成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。创建成员内部类对象的一般方式如下:
//第一种方式
外部类.内部类 对象名 = new 外部类().new 内部类();
//第二种方式
外部类 外部类对象名= new 外部类();
内部类 对象名 = 外部类对象.new 内部类();
内部类
-
内部类比外部类多了三个访问权限:
- private protected static
内部类分为:
-
非静态内部类,又称为成员内部类(未使用static修饰)
- 不能拥有静态成员
- 成员内部类可以无条件访问所在外部类的所有成员属性和成员方法(包括private成员和静态成员)。
- 当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量 外部类.this.成员方法
- 在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问
-
静态内部类(使用static修饰)
- 静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似。
- 它不能使用外部类的非static成员变量或者方法。因为在没有外部类的对象的情况下,可以创建静态内部类的对象。如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
-
局部内部类
- 把类定义在一个方法或者一个作用域内部,访问仅限于方法内或者该作用域内。
- 局部内部类就像是方法里面的一个局部变量一样,不能有 public、protected、private 以及 static 修饰符。
-
匿名内部类
- 适用于只需要使用一次的类。
- 通过接口或者抽象类创建匿名内部类。
- 匿名内部类也不能有访问修饰符和 static 修饰符。
- 匿名内部类是唯一一种没有构造器的类。正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。
- 一般来说,匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。
注: 局部内部类和匿名内部类只能访问局部final变量
特殊情况:关于成员内部类的继承问题
一般来说,内部类是很少用来作为继承用的。但是当用来继承的话,要注意两点:
1)成员内部类的引用方式必须为 Outter.Inner
2)构造器中必须有指向外部类对象的引用,并通过这个引用调用super()。这段代码摘自《Java编程思想》
class WithInner {
class Inner{
}
}
class InheritInner extends WithInner.Inner {
// InheritInner() 是不能通过编译的,一定要加上形参
InheritInner(WithInner wi) {
wi.super(); //必须有这句调用
}
public static void main(String[] args) {
WithInner wi = new WithInner();
InheritInner obj = new InheritInner(wi);
}
}