重载与重写
重载:参数类型 || 参数个数 || 参数顺序任意条件不同即可(仅返回类型不同是无法重载的)
重写:1)子类继承父类 2)重写父类成员方法实现内容 3)重写方法权限不能降低(public/protected)
4)重写的返回值类型必须是父类同一方法返回值类型的子类
super关键字:super()调用父类构造器和被隐藏的成员
instanceof判断对象类型:
myobject(对象引用) instanceof ExampleClass(某个类)
返回true,myobject是ExampleClass实例对象,反之不是.
对象类型转换
向上转型
//向上转型操作
class Quadrangle{
static void draw(Quadrangle q) {
System.out.println("输出此方法");
}
}
public class Parallelogram extends Quadrangle {
public static void main(String[] args) {
Parallelogram p = new Parallelogram();
draw(p); //相当于Quadrangle q =new Parallelogram();
//可改写为draw(new Parallelogram());
}
}
向下转型
//向下转型操作
class Quadrangle{
}
public class Parallelogram extends Quadrangle {
public static void main(String[] args) {
Quadrangle q = new Parallelogram();
//Parallelogram p = q;
//将父类对象赋予子类对象,这种写法是错误的
//将父类对象赋予子类对象,并强制转换为子类型,这种写法是正确的
Parallelogram p = (Parallelogram) q;
}
}
多态
在父类中封装处理的方法,继承的子类对象使用"向上转型",实例化各子类对象在父类中执行.
多态使程序员无须在子类中定义执行相同功能的方法,避免代码冗余.
//四边形类
class Quadrangle {
//实例化保存四边形对象的数组对象
private Quadrangle[] qtest = new Quadrangle[6];
private int nextIndex = 0;
//定义draw()方法,参数为四边形对象
public void draw(Quadrangle q) {
final int t = 0;
if(nextIndex < qtest.length) {
qtest[nextIndex] = q;
System.out.println(nextIndex);
nextIndex++;
}
}
public static void main(String[] args) {
//实例化两个四边形对象,用于调用draw()方法
Quadrangle q = new Quadrangle();
q.draw(new Square()); //正方形对象为参数
q.draw(new Parallelogramgle()); //平行四边形对象为参数
}
}
//正方形类继承四边形类
class Square extends Quadrangle{
public Square() {
System.out.println("正方形");
}
}
//平行四边形类继承四边形类
class Parallelogramgle extends Quadrangle{
int test = 0;
public Parallelogramgle() {
System.out.println("平行四边形");
}
}
抽象
final不修饰抽象方法/类,static不修饰抽象方法
抽象类不可以实例化对象,除了被继承没有任何意义
抽象类被继承后需要实现其中所有的抽象方法.
抽象类可有抽象方法和非抽象方法,也可以没抽象方法
抽象方法没有方法体,本身无意义除非被重写,抽象方法只存在于抽象类
一个抽象类是抽象类子类时,可重写父类抽象方法,也可继承父类抽象方法
抽象类声明对象,该对象可以成为其子类对象的上转型对象,该对象从而可调用子类重写的方法
public abstract class Test{
abstract void testAbstract(); //定义抽象方法
}
接口
接口中所有方法都是抽象方法(无方法体,全是public abstract修饰,其他权限不被编译器认可)
任何字段都自动static final == 常量(public static final)
非abstract类实现接口要重写接口所有方法
抽象类可重写接口的方法,也可直接拥有接口的方法(不用重写所有方法)
可用接口名访问接口的常量,实现接口的类可以直接使用接口的常量
一个源文件可由类和接口组成
子接口继承父接口全部常量和方法
//接口定义
public interface drawTest{ //同类一样,public只在同名文件定义
void draw();
//任何字段都是static final
//接口中,方法必须定义为public/abstract,即使不声明也是public
}
//类实现接口
public class Test1 extends Test2 implements drawTest{
}
多态+接口例子
interface drawTest { //接口
void draw();
}
//定义平行四边形类,继承四边形类,实现drawTest接口
class ParallelogramgleUseInterface extends QuadrangleUseInterface
implements drawTest{
public void draw() { //实现类必须实现接口的所有方法
System.out.println("平行四边形.draw()");
}
void doAnyThing() { //子类可选择性重写父类方法
System.out.print("01");
}
}
//定义正方形
class SquareUseInterface extends QuadrangleUseInterface
implements drawTest{
public void draw() {
System.out.println("正方形.draw()");
}
void doAnyThing() {
System.out.print("02");
}
}
class doAnyThing extends QuadrangleUseInterface{
void doAnyThing() {
System.out.println("doAnyThing.doAnyThing()");
}
}
public class QuadrangleUseInterface { //定义四边形类
void doAnyThing() {
}
public static void main(String[] args) {
drawTest[] d = { //接口,抽象类也可以向上转型操作
new SquareUseInterface(),
new ParallelogramgleUseInterface(),
};
for(int i = 0; i < d.length; i++) {
d[i].draw(); //调用draw()方法
}
}
}
final
final定义的变量为常量
final double PI =3.14 //final声明变量时必须赋值,之后赋值不被编译器接受
final可修饰常量、对象引用(对象值可改变,引用不可变)、数组,三者在main()中不可改变
既被static又被final的字段只占据不能改变的存储空间
final变量example:
FinalData类:
import static java.lang.System.out;
import java.util.Random;
class Test{
int i =0;
}
public class FinalData {
static Random rand = new Random();
private final int VALUE_1 = 9; //final常量
private static final int VALUE_2 = 10; //final、static常量
private final Test test = new Test(); //final引用
private Test test2 = new Test(); //非final引用
private final int[] a = {1, 2, 3, 4, 5, 6}; //final数组
private final int i4 = rand.nextInt(10000); //final常量
//i5:即是static又是final的字段占据一段不可改变的存储空间!!!
private static final int i5 = rand.nextInt(2);
public FinalData() {
System.out.println("输出FinalData");
}
public String toString() {
return i4 + " " + i5 + " ";
}
public static void main(String[] args) {
FinalData data = new FinalData();
// data.test = new Test();
//可以对指定为final的引用中的成员变量赋值
//但不能将定义为final的引用指向其他引用
// data.VALUE_2++; //不能改变定义为final的常量值
data.test2 = new Test(); //可以将非final引用指向其他引用
for(int i = 0; i < data.a.length; i++) {
// 不能对定义为final的数组赋值
// a[i] = 9;
}
out.println(data);
out.println("data2");
out.println(new FinalData());
out.println(data);
}
}
常量真正不可改变使用:static final
全局常量用:public static final
声明成员变量没赋值称为空白final,需在构造器中赋值(空白final)
FinalStaticData类:
import static java.lang.System.out;
import java.util.Random;
public class FinalStaticData {
private static Random rand = new Random();
// 随机产生0~10(包括0,不包括10)之间的随机数,赋值给定义为final的a1
private final int a1 = rand.nextInt(10); //创建新对象时初始化
// 随机产生0~10(包括0,不包括10)之间的随机数,赋值给定义为static final的a2
private static final int a2 = rand.nextInt(10); //恒定不变的内存区域
public static void main(String[] args) {
//实例化一个对象
FinalStaticData fdata = new FinalStaticData();
out.println(fdata.a1);
out.println(fdata.a2);
//实例化另一个对象
FinalStaticData fdata2 = new FinalStaticData();
out.println(fdata2.a1);
out.println(fdata2.a2);
}
}
final方法不被重写,private方法隐式为final类型
父类的private final方法不能重写,在子类中可以生成一个同名新方法.
FinalMethod类:
class Parents{
private final void doit() {
System.out.println("父类.doit");
}
final void doit2() {
System.out.println("父类.doit2");
}
public void doit3() {
System.out.println("父类.doit3");
}
}
class Sub extends Parents{
public final void doit() { //在子类中定义一个新方法doit()
System.out.println("子类.doit()");
}
// final void doit2() { //final方法不能重写
// System.out.println(子类.doit2());
// }
public void doit3() {
System.out.println("子类.doit3()");
}
}
public class FinalMethod {
public static void main(String[] args) {
Sub s = new Sub();
s.doit();
Parents p = s; //向上转型操作
// p.doit(); //不能调用private方法
p.doit2();
p.doit3();
}
}
final类不被继承&&不能任何改动
final类中成员变量可定义为final/非final,final类中所有方法隐式设置为final.
内部类
定义:在类中定义的类.
分为:成员内部类、局部内部类、静态内部类、匿名类.
成员内部类
内部类可以随意使用外部类成员方法、成员变量(尽管类成员是private).
内部类成员只有在内部类范围内可知,不被外部类使用.
内部类对象依赖于外部类对象
内部类对象实例化:外部类/外部类的非静态方法中实现 (Example:OuterClass.java)
public class OuterClass {
InnerClass in = new InnerClass(); //外部类实例化内部类对象引用
public void ouf(){
in.inf();
}
class InnerClass{
InnerClass(){
System.out.println("这里是InnerClass()");
}
public void inf(){ //内部类成员方法
System.out.println("这里是内部类inf()");
}
int y = 1; //内部类成员变量
}
public InnerClass doit(){
// y = 4; //报错,外部类不可以直接访问内部类成员变量
in.y = 4;
System.out.println("这里是doit()");
return new InnerClass();
}
public static void main(String[] args){
OuterClass out = new OuterClass();
//内部类的对象实例化操作必须在外部类或外部类的非静态方法中实现
OuterClass.InnerClass in = out.doit();
OuterClass.InnerClass in2 = out.new InnerClass();//内部类对象依赖于外部类对象
}
}
内部类向上转型为接口
非内部类不能声明private、protected.
一般类不能多次实现接口同一方法,但可以定义多个内部类以不同方式实现接口中同一方法
对子类隐藏内部类实现细节只留下一个接口和外部类,子类通过接口引用调用内部类实现接口的方法
interface OutInterface{ //定义一个接口
public void f();
}
public class InterfaceInner{
public static void main(String[] args){
OuterClass2 out = new OuterClass2(); //实例化一个OuterClass2对象
OutInterface outinter = out.doit(); //调用doit方法,返回一个OutInterface接口
outinter.f(); //调用第一个内部类f()方法
OutInterface outinter1 = out.doit1(); //实例化第二个内部类
outinter1.f(); //调用第二个内部类f()方法
OuterClassSon w = new OuterClassSon(); //实例化子类
try{
w.ww();
w.f();
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println("结束");
}
}
}
class OuterClass2{
//定义一个内部类实现OutInterface接口
private class InnerClass implements OutInterface{ //第一个内部类InnerClass
InnerClass(String s){ //内部类构造器
System.out.println(s);
}
@Override
public void f() { //实现接口f()方法
System.out.println("访问内部类中的f()方法\n");
}
}
public OutInterface doit(){ //定义一个方法,返回值类型为OutInterface接口
return new InnerClass("访问内部类构造方法"); //实例化InnerClass对象向上转型为接口引用
}
private class InnerClass1 implements OutInterface{ //第二个内部类InnerClass1
InnerClass1(String s){ //内部类构造器
System.out.println(s);
}
@Override
public void f() { //实现接口f()方法
System.out.println("f()方法\n");
}
}
public OutInterface doit1(){ //定义一个方法,返回值类型为OutInterface接口
return new InnerClass1("访问内部类1构造方法"); //实例化InnerClass对象向上转型为接口引用
}
}
class OuterClassSon extends OuterClass2 implements OutInterface{
void ww(){
OuterClass2 test = new OuterClass2();
OutInterface s = test.doit();
s.f();
}
@Override
public void f() {
System.out.println("子类实现接口的f()方法\n");
}
}
使用this关键字获取内部类与外部类的引用
在外部类、内部类成员变量同名使用this的情况:
/**
* 无添加前缀为局部变量
* this调用内部类变量
* 外部类名+this调用外部变量
*/
public class TheSameName {
private String x = "外部";
public static void main(String[] args){
TheSameName n = new TheSameName();
Inner i = n.new Inner();
i.doit("局部形参");
}
private class Inner{
private String x = "内部";
public void doit(String x){
System.out.println(x); //调用形参x
System.out.println(this.x); //调用内部类变量x
System.out.println(TheSameName.this.x); //调用外部类变量x
}
}
}
内存中所有对象放在堆中,方法及方法形参/局部变量放在栈中.
局部内部类
定义:内部类定义在方法中/任意作用域中.
interface OutInterface2 {
}
public class OutInterface3 {
String x = "balabala";
public OutInterface2 doit(final String x){//final变量生命周期超出方法运行生命周期
//在doit方法中定义一个内部类
class InnerClass2 implements OutInterface2{
InnerClass2(String s){
s = OutInterface3.this.x; //外部类变量,方法的局部变量使用:s = x;
System.out.println(s);
}
}
return new InnerClass2("doit");
}
public static void main(String[] args){
OutInterface3 out = new OutInterface3();
out.doit("hello");
}
}
内部类是方法的一部分而非外部类的一部分,所以方法的外部不能访问内部类,但内部类可以访问当前作用域的常量和外部类的所有成员.
匿名内部类
编译后生成"外部类名$序号.class",序号为1~n排列.
匿名类的所有实现代码都要在{}间编写.
return new A(){
内部类体实现代码 //使用默认构造器生成A接口对象
}; //分号代表创建引用表达式的结束
public interface OutInterface2 {
}
class OuterClass3 {
public OutInterface2 doit(final String x){ //doit()方法内部内部返回一个OutInterface2的引用
return new OutInterface2(){ //return语句创建一个内部类(匿名内部类无名称)实现接口的匿名类的对象
private int i = 0;
public int getValue(){
return i;
}
};
}
public static void main(String[] args){
OuterClass3 out = new OuterClass3();
out.doit("hello");
}
}
静态内部类
定义:内部类前+static.
静态内部类中可以声明static成员,非静态内部类不声明静态内部类.
静态内部类不可以使用外部类的非静态成员
创建静态内部类对象不需要依赖外部类对象,非静态内部类对象依赖外部类对象.
静态内部类对象不能访问非静态外部类对象.
public class StaticInnerClass {
static int x = 100;
static class Inner {
void doitInner() {
System.out.println("外部类" + x); //调用外部类成员变量需为static
}
}
public static void main(String[] args){
Inner c = new Inner(); //静态内部类对象不依赖外部类对象
c.doitInner();
}
}
减少额外代码,可把主方法写入静态内部类中.
内部类的继承
某个类继承内部类,必须给此类带参数(继承内部类的外部类引用)的构造方法
此类构造方法体带外部类引用.super(),为继承提供必要对象引用.
public class OutputInnerClass extends ClassA.ClassB{ //继承内部类
public OutputInnerClass(ClassA a){ //参数定义(父类的)外部类对象引用
a.super(); //调用父类(内部类)构造方法需要外部类对象引用
}
}
class ClassA{ //外部类
class ClassB{ //成员内部类
}
}