Java的第一遍学习笔记 面向对象高级

final

final可以修饰类、属性、方法和局部变量。

使用

1. 当不希望类被继承时,可以用final修饰。

2. 当不希望父类的某个方法被子类 重写 时,可以用final关键字修饰。

3. 当不希望类的某个属性的值被修改,可以用final修饰。

4. 当不希望某个局部变量被修饰,可以使用final修饰。

     public void test(){
         final int a = 10;
         a= 20;   //报错
     }

注意事项

1. final修饰的属性又叫常量,一般用 XX_XX_XX命名(比如 TAX_RATE)。

public final static TAX_RATE = 0.2;

2. final修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以在下列位置之一:(1)定义时  (2) 在构造器中  (3) 在代码块中(代码块相当于构造器的补充)

3. 如果final修饰的属性是静态的,则初始化位置只能是:(1) 定义时  (2) 在静态代码块,不能在构造器中赋值(因为可以用类名调用静态属性,并没有调用构造器)。

4. final类不能继承,但是可以创建对象(实例化)。

5. 如果类不是final类,但是含有final方法,虽然该方法不能重写,但是可以被继承。

    public static void main(String[] args) {
        Student a = new Student();
        a.test();  //输出父类的test方法
    } 

6. 一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法(因为根本就无法继承,也就没办法重写方法了)。

7. final不能修饰构造器。

8. final和static往往搭配使用,效率更高,不会导致类加载,底层编译器做了优化处理。

public class Person {
     public final static double PI = 3.14;
     static{
         System.out.println("类加载,调用静态代码块");
     }
}
public class Test {
    public static void main(String[] args) {
        System.out.println(Person.PI);   //只输出 3.14,不调用静态代码块
    }
}

9. 包装类(Integer,Double,Float,Boolean等)都是final,String也是final类。

抽象类

    当父类的一些方法不能确定时,可以用abstract关键字来修饰该方法,这个方法就是抽象方法,然后再用abstract来修饰该类,这个类就是抽象类。

abstract public class Person {
     public abstract void say();  //加分号
}

    所谓抽象方法就是没有实现的方法(没有方法体),当一个类中存在抽象方法时,需要将该类声明为abstract方法。一般来说,抽象类会被继承,由其子类来实现抽象方法。

简介

1. 用 abstract 关键字来修饰一个类时,这个类就叫抽象类。

访问修饰符 abstract 类名{}

2. 用 abstract 关键字来修饰一个方法时,这个方法就是抽象方法。

访问修饰符 abstract 返回类型 方法名(参数列表); //没有方法体

3. 抽象类的价值更多作用是在于设计,设计者设计好后,让子类继承并实现抽象类,在框架和设计模式使用较多(常考)。

注意事项

1. 抽象类不能被实例化。

2. 抽象类可以没有abstract方法,但只要类是abstract,那么它的方法即使不写abstract,也是抽象方法

3. 一旦类包含了abstract方法,则这个类必须声明为abstract。

4. abstract 只能修饰类和方法,不能修饰属性和其它的。

5. 抽象类可以有任意成员(因为抽象类还是类),比如:非抽象方法,构造器,静态属性等等。

6. 抽象方法不能有主体,即不能有大括号。

     public abstract void say(){}; //报错,不能有大括号

7. 如果一个类继承了抽象类,那么它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类。

 8. 抽象方法不能使用 private, final 和 static来修饰,因为这些关键字都是和重写相违背的。

private不能重写,static与重写无关。 

关于static可以看这个博客:关于abstract为什么不能和static连用_sinat_36695865的博客-CSDN博客

模板设计模式

abstract public class Template { //抽象类-模板设计模式
    public abstract void job(); //抽象方法
    public void calculateTime(){  //主体方法
        long start = System.currentTimeMillis();
        job();
        long end = System.currentTimeMillis();
        System.out.println("执行时间为:"+(end-start));
    }
}
public class AA extends Template{
    @Override
    public void job() {   //重写抽象方法
        int sum = 0;
        for (int i = 0; i < 1000000; i++) {
            sum += i;
        }
    }
}
public class Test {
    public static void main(String[] args) {
         AA a = new AA();
         a.calculateTime();  //直接调用方法
    }
}

    这个设计模式的好处就是 —— 把需要重写的方法做成 抽象方法写在抽象父类中,子类只需要把不同的代码重写即可,相同部分的方法写在抽象类中, 子类不需要动,在测试类中实例化对象直接调用即可。

接口

基本介绍

    接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些方法写出来。

interface 接口名{
    //属性
    //方法(1.抽象方法 2.默认实现方法 3.静态方法)
}  
class 类名 implements 接口名{
    //自己的属性
    //自己的方法
    //必须实现的接口抽象方法
}

注:1. 在Jdk7.0 之前,接口里的所有方法都没有方法体,即都是抽象方法(abstract可省略)2. Jdk8.0 后,接口可以有静态方法,默认方法,也就是说接口中可以有方法的具体实现。

public interface Interface01 {
    public int n1 = 10;
    public void h1();   //接口中可省略abstract
    default public void say(){  //默认方法,要加上关键字default
        System.out.println("调用say方法");
    }
    public static void hi(){   //静态方法
        System.out.println("打招呼");
    }
}

注意事项

1. 接口不能被实例化。

Interface01 a = new Interface01(); //报错

2. 接口中所有的方法都是public方法,接口中抽象方法可以不用abstract修饰

void h1();  //实际上是 public abstract void h1();

如何验证:

public class Teacher implements Interface01{
    @Override
    void h1() {}   //报错,因为根据继承关系,重写方法时不能减小范围,间接证明为public  
}

3. 一个普通类实现接口,就必须将该接口的所有抽象方法实现,快捷键:点击要实现接口的名字,按 Alt + Enter ,点击 Implement methods,然后选中要实现的方法。

4. 抽象类实现接口,可以不用实现接口的抽象方法。

5. 一个类可以同时实现多个接口,中间用逗号隔开。

class Person implements IB,IC {}

6. 接口中的属性,前面默认有 public static final 修饰符,必须初始化

7. 接口中属性的访问形式:接口名.属性名

System.out.println(Interface01.n1);

8. 一个接口不能继承其他的类,但是可以继承多个别的接口。

public interface Interface01 extends Interface02,Interface03 {}

9. 接口的修饰符只能是 public 和 默认,这点和类的修饰符是一样的。

private interface Interface01{} //报错,修饰符只能是public或默认

10. 用对象名可以调用接口中的属性(另外也可以用类名和接口名调用),但是IDEA没有提示。

public class Test {
    public static void main(String[] args) {
        Teacher a = new Teacher();
        System.out.println(Teacher.n1);
        System.out.println(Interface01.n1);
        System.out.println(a.n1);  //没有报错,证明可以用对象名调用
    }
}

11. 有继承还有接口的类,如果接口和父类某个属性重名,调用时要用接口名和super指定。 

public class Teacher extends Person implements Interface01 {
    public void show(){
        System.out.println(Interface01.x);  //输出接口的x
        System.out.println(super.x);        //输出父类的x
        System.out.println(x);  //报错,无法确定哪个x  
    }
}

与继承的比较

    当子类继承了父类,就自动的拥有父类的功能(类似父子关系),如果子类需要扩展功能,就可以通过实现接口的方式扩展(类似师徒关系)比如说金丝猴继承猴子类,拥有了一些猴子的属性,如果金丝猴想要游泳和飞翔,那么就需要实现鱼和鸟的接口。可以理解为:实现接口是对Java单继承机制的一种补充。

    继承的价值主要在于:解决代码的复用性和可维护性。

    接口的价值主要在于:设计好各种方法,让其它类去实现这些方法。继承是满足 is - a 关系,而接口只需要满足 like - a 关系即可,接口比继承更加灵活。并且接口在一定程度上实现代码解耦。

接口的多态性

1. 多态参数

       Usb接口参数既可以接收手机对象,又可以接收电脑对象,接口引用可以指向实现了接口的类的对象。

public interface Usb {  //接口
    void work();
}

public class Phone implements Usb{
    @Override
    public void work() {
        System.out.println("Usb在手机上工作");
    }
}

public class Computer implements Usb
    @Override
    public void work() {
        System.out.println("Usb在电脑上工作");
    }
}
public class Test {
    public static void main(String[] args) {
        Test a = new Test();
        Phone b = new Phone();
        Computer c = new Computer();
        a.show(b);   //接口的多态,类似向上转型
        a.show(c);
    }
    public void show(Usb a){  //形参是一个接口
        a.work();
    }
}

 2. 多态数组

public class Test {
    public static void main(String[] args) {
        Usb[] usbs = new Usb[2];
        usbs[0] = new Phone();
        usbs[1] = new Computer();
        for (int i = 0; i < 2; i++) {
            usbs[i].work();   //调用接口中的方法
            if(usbs[i] instanceof Phone){
                ((Phone) usbs[i]).call();   //类似向下转型,call是Phone类的独特方法
            }
        }
    }
}

  由于能调用什么方法是根据编译类型来的,因此想调用call方法需要用到向下转型(类似)。

3. 多态传递现象

interface IA{
    void say();
}
 
interface IB extends IA{  //IB接口继承自IA
    void hi();
}

public class Person implements IB{
     IA a = new Person();   //这里就用到了多态传递现象
     @Override
     public void say() {

     }
     @Override
     public void hi() {

     }    //方法必须全部实现
}

    很明显,Person类并没有实现IA接口,但是却可以用IA来实例化对象。原因是Person实现了IB接口,而IB接口继承自IA,Person类把IB和IA接口的方法全部实现,相当于实现了IA。

    简而言之,类需要把implements接口的方法,以及接口父类的方法全部实现,然后可以用接口以及接口的子类实例化对象。

内部类(难点、重点)

基本介绍

     一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类,嵌套内部类的类称为外部类,是我们类的第五大成员(五大成员:属性、方法、构造器、代码块、内部类内部类的最大特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。

class Outer{         // 外部类
    class Inner{     // 内部类
    
    }
}

class Other{         // 外部其它类

}

内部类的分类

1. 定义在外部类的局部位置上(方法/代码块内):A. 局部内部类(有类名) B. 匿名内部类(没有类名,重点)

2. 定义在外部类的成员位置上:A. 成员内部类(没用static修饰)B. 静态内部类(使用static修饰)

局部内部类

1. 可以直接访问外部类的所有成员,包括私有的。

2. 不能添加访问修饰符,因为它相当于一个局部变量,局部变量是不能使用修饰符的,但是可以使用final修饰,因为局部变量也可以使用final。

3. 作用域:仅仅在定义它的方法或代码块中。

4. 外部类 访问 局部内部类的成员:创建对象再访问(必须在作用域内)。

5. 局部内部类 访问 外部类成员:直接访问。

public class Outer {
    private int n1 = 10;
    public void say(){
        int n3 = 30;
        class Inner01{
            int n2 = n1;  //直接访问外部类成员
            public void show(){
                System.out.println("调用局部内部类的方法");
            }
        }
        Inner01 a = new Inner01();
        a.show();  //先创建对象再访问局部内部类的成员
    }
    Inner01 b = new Inner01();  //报错,已经不在局部内部类的作用域中了
}

6. 外部其它类不能访问 局部内部类(因为 局部内部类相当于一个局部变量)。

7. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用 外部类名.this.成员 去访问,其中 外部类名.this 相当于外部类

public class Outer {
    private int n1 = 10;
    private static String name = "张三";
    public void say(){
        int n1 = 30;
        class Inner01{
            int n1 = 1000;
            public void show(){
                System.out.println(n1);   //输出 1000,就近原则
                System.out.println(this.n1);  //输出 1000,用this还是就近原则
                System.out.println(Outer.this.n1); //输出 10,外部类定义的变量
                System.out.println(Outer.n1); //报错
            }
        }
        Inner01 a = new Inner01();
        a.show();
    }
}

class Others{
    Inner01 a = new Inner01();  //报错,外部其他类 不能访问 局部内部类
}

匿名内部类

    定义在外部类的局部位置,并且没有类名。(1)本质是类 (2)该类没有名字 (3)同时还是一个对象。

接口:

new 类或接口(参数列表){  //构造器
    类体
}; //注意返回一个指向该类或接口的实例
/* 需求:用IA接口创建对象
   传统方法:写一个类实现该接口,并创建对象。
   但现在的要求是:创建的类只使用一次,后面就不再使用了。
   可以使用 匿名内部类 来简化开发。
*
*/
public class Outer {
    public void create(){   //写在方法内
        IA tiger = new IA(){
            @Override
            public void say() {
                System.out.println("老虎嗷嗷叫");
            }
        };  //匿名内部类,tiger的编译类型为IA,tiger的运行类型就是匿名内部类(也就是 Outer$1)
    }
}

interface IA{
    void say();
}

  实际上Jdk底层会给 匿名内部类 分配一个类名,分配的方法为 外部类类名+$(可用tiger的getClass方法查看),然后立即创建一个 Outer$1实例,并且把地址赋给 tiger。

class Outer$1 implements IA {
    @override
    public void cry(){
        System.out.println("老虎嗷嗷叫");  
    }
}

类:

/*
   a的编译类型为 Person1
   a的运行类型为 Outer$1(也就是整个匿名内部类)
   底层会创建一个Person1实例 Outer$1,并返回给a
   class Outer$1 extends Person1{    // 底层创建的类
        @Override
        public void say() {
            System.out.println("在匿名内部类重写父类方法");
        }
   }
   Outer$1 XXX = new Outer$1("Jack");
   Person1 a = XXX;  //XXX被销毁,Outer$1也被销毁
*/

public class Outer {
    public void create(){
        Person1 a = new Person1("Jack") {
            @Override
            public void say() {
                System.out.println("在匿名内部类重写父类方法");
            }
            public void hello(){
                System.out.println("调用匿名内部类独有的方法");
            }  //无法调用,因为编译类型为Person1,不能调用子类独有的方法
        };
        //匿名内部类,不加大括号就是正常的创建类,运行类型为Person1,而加了就是匿名内部类
        a.say();
        System.out.println(a.getClass()); //输出a的运行类型,为 Outer$1
    }
}

class Person1 {
    private String name;
    public Person1(String name) {
        this.name = name;
    }
    public void say(){
    }
}

注意事项

1. 匿名内部类既是一个类的定义,同时它本身也是一个对象(本身就是个返回对象)。因此从语法上看,它既有定义类的特征,也有创建对象的特征,因此可以直接调用匿名内部类方法

        new Person1("Jack") {
            @Override
            public void say() {
                System.out.println("在匿名内部类重写父类方法");
            }
        }.say();   //可以new之后直接调用

3. 可以直接访问外部类的所有成员,包含私有的。

4. 不能添加访问修饰符,因为它的地位就是一个局部变量。

5. 作用域:仅仅在定义它的方法或代码块中。

6. 匿名内部类 访问 外部类成员:直接访问。

7. 外部其它类 不能访问 匿名内部类(因为匿名内部类建立之后就销毁了)。

8. 如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用 外部类名.this.成员 去访问。

实例

当作实参直接传递,简洁高效。

public class Outer{
    public static void f1(IL il){
        il.show();
    }

    public static void main(String[] args) {
        f1(new IL() {     // 把匿名内部类当作参数导入
            @Override
            public void show() {
                System.out.println("导入匿名内部类");
            }
        });
    }
}

interface IL{
    void show();
}

对比一下传统方法

public class Outer{
    public static void f1(IL il){
        il.show();  
    }

    public static void main(String[] args) {
        Picture a = new Picture();  // 创建一个对象
        f1(a);  // 利用接口的多态
    }
}

interface IL{
    void show();
}

class Picture implements IL{  // 定义一个类实现接口
    @Override
    public void show() {     
        System.out.println("传统方法");
    }
}

成员内部类

成员内部类定义在外部类的成员位置,并且没有static修饰。

1. 可以直接访问外部类的所有成员包含私有的。

2. 可以添加任意访问修饰符,因为它的地位就是一个成员。

3. 作用域:和外部类的其他成员一样,为整个类。

4. 成员内部类 访问 外部类成员:直接访问。

5. 外部类 访问 成员内部类:创建对象再访问。

class Outer{
    private int n1 = 10;
    class inner{
        public void show(){
            System.out.println(n1);  //内部成员类 调用 外部类(私有也可以访问)
        }
    }
    public void say(){
        inner a = new inner();  // 先创建对象                    
        a.show();   // 外部类 调用 内部成员类
    }
}

6. 外部其它类 访问 成员内部类

第一种方式:把 Inner01 看作 Outer01 的成员,Outer01.Inner01 为编译类型,用外部类实例new

class Others{
    Outer01 outer = new Outer01();
    Outer01.Inner01 inner = outer.new Inner01();  //相当于把 Inner01当作 Outer01的成员
}

第二种方式:在外部类中编写一个方法,可以返回 Inner01 对象

public Inner01 getInner01(){
    Inner01 a = new Inner01();
    return a;
}  //编写方法

class Others{
    Outer01 outer01 = new Outer01();
    Outer01.Inner01 inner01 = outer01.getInner01();  //用对象实例调用方法
}

7. 如果外部类和内部类的成员重名时,内部类访问遵循就近原则,如果想访问外部类的成员,则可以使用 外部类名.this.成员 去访问

静态内部类

静态内部类定义在外部类的成员位置,并且有static修饰。

1. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员

2. 可以添加任意访问修饰符,因为它的地位就是一个成员。

3. 作用域:同其他的成员,为整个类体。

4. 静态内部类 访问 外部类:直接访问所有静态成员。

5. 外部类 访问 静态内部类:先在外部类中创建对象再访问。

6. 外部其它类 访问 静态内部类:

第一种方法:因为是静态内部类,可以通过类名直接访问(满足访问权限)。

    Outer01.Inner01 inner01 = new Outer01.Inner01(); //直接用类名new

第二种方法:编写一个方法,可以返回静态内部类的对象实例。

public Inner01 create(){
    return new Inner01();  //返回一个 静态内部类的实例
} 

class Others{
    Outer01 a = new Outer01();
    Outer01.Inner01 inner01 = a.create();  //调用方法返回实例
}

7. 如果外部类和内部类的成员重名时,内部类访问遵循就近原则,如果想访问外部类的成员,则可以使用 外部类名.成员 去访问(因为 外部类名.this 是对象名,而静态变量可以用类名访问

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java面向对象程序设计第三版耿祥义第一章主要介绍了Java的基础知识和面向对象的概念。 1. Java语言的特点 Java语言是一种面向对象的编程语言,具有以下特点: - 简单易学:Java语言的语法似C++,但是去掉了C++中比较难理解的特性,使得Java容易学习和使用。 - 面向对象Java语言是一种纯面向对象的编程语言,所有的程序都是由对象组成的。 - 平台无关性:Java语言可以在不同的操作系统和硬件平台上运行,只需要安装相应的Java虚拟机即可。 - 安全性:Java语言的安全性非常高,可以在不信任的环境下运行程序,避免了一些安全漏洞。 - 高性能:Java语言的运行速度比较快,且可以通过各种优化技术来提高性能。 2. 面向对象的概念 面向对象是一种软件设计的思想,其核心是将问题看作是由对象组成的。对象是指具有一定属性和行为的实体,属性是对象的特征,行为是对象的动作。 在面向对象的设计中,需要考虑以下几个方面: - 的设计:是创建对象的模板,需要定义的属性和方法。 - 对象的创建:创建对象时,需要使用new关键字来调用的构造方法。 - 对象的访问:访问对象的属性和方法时,需要使用点号操作符来进行访问。 - 继承和多态:继承是指一个可以继承另一个的属性和方法,多态是指同一种行为可以用不同的方式实现。 3. Java的基础知识 Java语言的基础知识包括数据型、运算符、流程控制语句等。 - 数据型:Java语言的数据型包括基本数据型和引用数据型。基本数据型包括整型、浮点型、字符型和布尔型,引用数据型包括、接口、数组等。 - 运算符:Java语言的运算符包括算术运算符、关系运算符、逻辑运算符、位运算符等。 - 流程控制语句:Java语言的流程控制语句包括if语句、switch语句、for循环、while循环、do-while循环等。 4. Java程序的基本结构 Java程序的基本结构包括定义、方法的定义和语句块的定义。 - 定义Java程序的基本组成单元,需要使用class关键字定义。 - 方法的定义:方法是中的一个函数,用于实现特定的功能,需要使用方法名、参数列表和返回值型来定义方法。 - 语句块的定义:语句块是一组语句的集合,需要使用大括号来定义语句块。 总的来说,Java面向对象程序设计第三版耿祥义第一章介绍了Java语言的基础知识和面向对象的概念,为后续的学习打下了基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值