Java面向对象编程进阶--其他

Java面向对象编程进阶

  • 抽象方法和抽象类
  • 接口(interface)
    • 接口的作用
    • 接口的定义和使用
    • 接口的多继承
  • 内部类
    • 内部类概念
    • 内部类的作用
    • 内部类的分类
      • 1 成员内部类(非静态内部类和静态内部类)
      • 2 匿名内部类
      • 3 局部内部类
  • 字符串String
    • String类和常量池(内存分析相关)
    • String类中常用的方法
  • 设计模式简要了解

抽象方法和抽象类

抽象方法
使用abstract修饰的方法,没有方法体,只有声明。它定义的是一种规范,告诉子类必须要给抽象方法提供具体的实现
抽象类
包含抽象方法的类就是抽象类。抽象类通过abstract方法定义规范,要求子类必须定义具体实现。
抽象类使用要点:

  • 有抽象方法的类只能定义成抽象类
  • 抽象类不能实例化,不能用new来实例化抽象类
  • 抽象类可以包含属性、方法和构造器,但构造器不能用new来实例化,只能被子类调用
  • 抽象类只能用来被继承
  • 抽象方法必须被子类实现

具体用法给出示例:

abstract class A{
     
    int num;
    abstract public void say();
}
class B extends A{
     //这里必须实现say方法,否则编译错误
    public void say(){
     
        System.out.println("我实现了父类(抽象类)的方法!");
    }
    public void end(){
     
        System.out.println("就到这里结束啦");
    }
}
public class Study{
     
    public static void main(String[] args) {
     
        //A a = new A();这里会编译错误,显示A是抽象的,不可被实例化
        B b = new B();
        b.num = 5;
        System.out.println(b.num);
        b.say();b.end();
    }
}

在这里插入图片描述

接口(interface)

接口就是一种规范,他定义了一组规则。就比如说,你是一个适龄儿童、少年,那么你就必须接受九年制义务教育,这是国家统一的规则是吧。
接口从本质上来讲还是类,他像是一种契约,如同法律,一旦制定,大家都要做个遵纪守法的好公民。
Ps.面向对象的精髓是对对象的抽象,最能体现这一点的就是接口。

接口的作用

接口是比抽象类还抽象的抽象类,更加规范地对子类进行约束,全面、专业地实现了规范和具体实现的分离。接口不提供任何实现,接口中所有方法都是抽象方法,接口完全面向规范,规定了一批类具有的公共方法规范。(想要更好的理解的话还是要去主动实现,这样更加深刻和直观)
关于普通类、抽象类和接口的区别:

  • 普通类:具体实现
  • 抽象类:具体实现、规范(抽象方法)
  • 接口:规范

接口的定义和使用

接口声明格式:

[访问修饰符] interface 接口名 [extends 父接口1,父接口2···]{
     //在看到这里的时候是不是发现了多继承?这在后面会写到
	常量定义;
	方法定义;
}
  • 访问修饰符只能是public或默认设置
  • 接口可以多继承
  • 接口中的属性只能是常量,总以(默认)public static final修饰,不写就默认为是
  • 接口中的方法只能是public abstract,不写就默认为是
  • 子类通过implements来实现接口中的规范
  • 接口不能创建实例,但是可用于声明引用变量类型
  • 一个类实现了接口,必须实现接口中的所有方法,并且这些方法只能是public的

具体的使用如下:

public class Study{
     
    public static void main(String[] args) {
     
        new LittleOne().study();
        new LittleOne().help();
        new Programmer().work();
        new Programmer().help();
        //student a = new student();错错错
        student a = new LittleOne();//对对对,这是向上自动转型
        ((LittleOne)a).studyagain();//复习复习,这是向下强制转型
        adult b = new Programmer();
        ((Programmer)b).workagain();
    }
}
interface student{
     
    int age = 10;//public static final常量
    void study();//public abstract抽象方法
}
interface adult{
     
    int age = 30;
    void work();
}
interface Characteristic{
     
    String ch = "善良";
    void help();
}
class LittleOne implements student, Characteristic{
     //如果方法不是全部都实现了就会编译错误
    public void study(){
     
        System.out.println("好好学习天天向上!");
    }
    public void help(){
     
        System.out.println("助人为乐!");
    }
    public void studyagain(){
     
        System.out.println("我又来学习了!");
    }
}
class Programmer implements adult, Characteristic{
     
    public void work(){
     
        System.out.println("我变秃了,也变强了!");
    }
    public void help(){
     
        System.out.println("助人为乐!");
    }
    public void workagain(){
     
        System.out.println("我又来变强了!");
    }
}

输出结果如下
Java面向对象编程进阶--其他_第1张图片

接口的多继承

接口完全支持多继承。子接口扩展某个父接口,会获得父接口中所定义的一切。
实现如下:

public class Study{
     
    public static void main(String[] args) {
     
        f ff = new f();
        ff.s1();ff.s2();ff.s3();
    }
}
interface A{
     
    int a = 5;
    void s1();
}
interface B{
     
    int b = 10;
    void s2();
}
interface C extends A, B{
     
    int c = 20;
    void s3();
}
class f implements C{
     
    public void s1(){
     
        System.out.println(a);
    }
    public void s2(){
     
        System.out.println(b);
    }
    public void s3(){
     
        System.out.println(c);
    }
}

输出如下
在这里插入图片描述

内部类

内部类是一种特殊的类,它是定义在一个类的内部的类。

内部类概念

一般情况下,类是一个独立的单元,在有些情况下,则把一个类放在另一个类的内部来定义,称作内部类。内部类可以用public、default、protected和private修饰,而外部的顶级只能用public和default来修饰。下面给出内部类的演示:

class Outer{
     
    private int num = 99;
    public void print(){
     
        System.out.println(num);
    }
    public class Inner{
     
        private int num = 999;//内部类中可以声明与外部类同名的属性和方法
        public void print(){
     
            System.out.println(num);
        }
    }
}

内部类只是一个编译时的概念,编译成功后会生成两个字节码文件Outer.class和Outer$Inner.class。

内部类的作用

  • 提供更好的封装,只能由外部类直接访问,而不允许同一个包中的其他类访问
  • 内部类可以直接访问外部类的私有属性,内部类被当做其外部类的成员。但是外部类不能访问内部类的内部属性和方法
  • 接口只是解决了多重继承的部分问题,内部类使得多重继承的解决方案更完整

在只为外部类提供服务的情况下可以优先考虑使用内部类
使用内部类间接实现多继承

内部类的分类

1 成员内部类(非静态内部类和静态内部类)

成员内部类可以使用public、defaule、protected和private修饰。
①非静态内部类
1°非静态内部类必须寄存在一个外部类的对象里。非静态内部类对象单独属于外部类的某个对象。
2°非静态内部类可以直接访问外部类的成员(属性和方法),但是外部类不能直接访问非静态内部类成员。
3°非静态内部类不能有静态方法、静态属性和静态初始化块。
4°外部类的静态方法、静态代码不能访问非静态内部类,包括不能使用非静态内部类定义变量,创建实例。
5°成员变量访问:

  • 内部类里的方法的局部变量:变量名
  • 内部类属性:this.变量名
  • 外部类属性/方法:外部类名.this.变量名/方法

6°内部类的访问:

  • 在外部类中定义内部类:new 内部类名()
  • 在外部类以外的地方使用非静态内部类:外部类名.内部类名 引用变量名 = new 外部类名().new 内部类名()

示例如下:

public class Study{
     
    public static void main(String[] args) {
     
        Outer a = new Outer();
        a.print();//外部类的方法
        Outer.Inner b = new Outer().new Inner();
        b.print();//内部类方法
        Outer.Inner c = a.new Inner();
        c.print();//内部类方法
    }
}
class Outer{
     
    private int num = 3;
    //Inner i = new Inner();//在外部类中定义内部类
    public void print(){
     
        System.out.println("外部类的成员变量->" + num);
    }
    public class Inner{
     
        int num = 36;
        public void print(){
     
            int num = 369;
            Outer.this.print();
            System.out.println("内部类方法里的局部变量->" + num);
            System.out.println("内部类的成员变量->" + this.num);
            System.out.println("外部类的成员变量->" + Outer.this.num);
        }
    }
}

输出如下
Java面向对象编程进阶--其他_第2张图片
②静态内部类
1°定义方式:

Static class ClassName{
     
	//类体
}

2°使用要点:

  • 一个静态内部类对象的存在,并不一定存在对应的外部类对象,因此,静态内部类的实例方法不能直接访问外部类的实例方法
  • 静态内部类可以看做是外部类的一个静态成员,因此,外部类的方法中可以通过“静态内部类.名字”的方法访问静态内部类的静态成员,通过new 静态内部类()访问静态内部类的实例

示例如下

public class Study{
     
    public static void main(String[] args) {
     
        Outer a = new Outer();
        a.print();//外部类的方法
        //通过new 外部类名.内部类名()来创建内部类对象
        Outer.Inner b = new Outer.Inner();
        b.print();
    }
}
class Outer{
     
    private int num = 3;
    public void print(){
     
        Inner i = new Inner();//可以访问内部类的成员和方法
        System.out.println("外部类的成员变量->" + num);
        System.out.println("内部类成员变量->" + i.num);
        i.print();
    }
    //相对于外部类的一个静态成员
    static public class Inner{
     
        int num = 36;
        public void print(){
     
            int num = 369;
            System.out.println("内部类方法里的局部变量->" + num);
            System.out.println("内部类的成员变量->" + this.num);
            //System.out.println("外部类的成员变量->" + Outer.this.num);//不能直接访问外部类成员
        }
    }
}

输出如下
Java面向对象编程进阶--其他_第3张图片

2 匿名内部类

匿名内部类适合哪种只需要使用一次的类,例如键盘监听等操作。
匿名内部类的语法格式如下:

new 父类构造器(实参类表)/实现接口(){
     
	//匿名内部类类体
}

利用键盘监听器操作的演示如下

this.addWindowListener(new WindowAdapter(){
     
	@override
	public void windowClosing(WindowEvent e){
     
		System.exit(0);
	}
});//看不懂也没关系,只是个演示而已
this.addKeyListener(new KeyAdapter(){
     
	@override
	public void keyPressed(KeyEvent e){
     
		myTank.keyPressed(e);
	}
	@override
	public void keyReleased(KeyEvent e){
     
		myTank.keyReleased(e);
	}
});//这两个大括号里就是匿名内部类的写法

匿名匿名,连名字都没有就没有构造器了。还有就是匿名内部类没有访问修饰符。

3 局部内部类

局部内部类定义在方法的内部,作用于只限于本方法,离开该方法就会失效。局部内部类主要是用来解决比较复杂的问题。(局部内部类在开发中很少应用)
示例如下

public class Study{
     
    public void func(){
     
        class Inner{
     
            public void fun(){
     
                System.out.println("6666666");
            }
        }
        new Inner().fun();
    }
    public static void main(String[] args) {
     
        new Study().func();
    }
}

输出如下
在这里插入图片描述

字符串String

String类又称为不可变字符序列。什么事不可变呢?如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的。不能改变状态的意思是,不能改变对象内的成员变量,包括基本数据类型的值不能改变,引用类型的变量不能指向其他的对象,引用类型指向的对象的状态也不能改变。给出下面的示例:

public class Study{
     
    public static void main(String[] args) {
     
        String s = "abcd";
        System.out.println(s);
        s = "1234";
        System.out.println(s);
    }
}

结果如下
在这里插入图片描述
这里的s改变了那为什么又叫做不可改变呢?
我们来看图
Java面向对象编程进阶--其他_第4张图片
Java面向对象编程进阶--其他_第5张图片
s是一个引用,一开始s指向的是对象abcd的地址,而后又指向新的对象1234的地址,在这个过程中abcd还存在于内存中,并没有被改变,只不过是s指向了新对象而已。
String位于java.lang包中,Java程序默认导入该包下的所有类。
Java字符串是Unicode字符序列,而非C/C++中的ASCII码。Java中没有内置的字符串类型,而是在标准的Java库中提供了预定义的String类,每个用双引号括起来的字符都是String类的一个实例。
字符串的连接

String s1 = "Hello";
String s2 = "World";
String s = s1 + s2; // s = "HelloWorld";
string s3 = "This " + 18;// 输出的s3是This 18

String类和常量池(内存分析相关)

(我觉得这一块部分要深入了解的话等学完java的基础后再去学习深入理解JVM,这里先做简单的介绍和了解)
常量池有三种:
1.全局字符串常量池(String Pool)
全局字符串常量池中放的内容是在类加载完成后存到Stirng Pool中的,在每个VM中只有一份,存放的是字符串常量的引用值(在堆中生成字符串对象实例)。
2.class文件常量池(Class Constant Pool)
class常量池是在编译时每个class都有的,在编译阶段,它存放的是常量(文本字符串、final常量等)和符号引用。
3.运行时常量池(Runtime Constant Pool)
运行时常量池是在类加载完成后,将每个class常量池中的符号引用值转存到运行时常量池中,也就是说,每个class都有一个运行时常量池,类在解析之后,将符号引用替换成直接引用,与全局常量池中的引用保持一致。
常量池演示和分析:

String s1 = "abc";
string s2 = new String("def");
String s3 = "abc";
String s4 = str2.intern();//返回String Pool中的"def"引用值
String s5 = "def";
System.out.println(s1 == s3);//true
System.out.println(s2 == s4);//false
System.out.println(s4 == s5);//true

上面的代码在编译后,会在这个类的class常量池中存放一些字符;当类加载后,将class常量池中存放的字符引用转存到运行时常量池中;然后经过验证、准备阶段后,在堆中生成驻留字符串的实例对象(即s1所指向"abc"的实例对象);再将这个对象的引用存放全局字符串常量池中;最后在解析阶段,把运行时常量池中的字符引用替换成直接引用,于是直接查询String Pool,保证String Pool里地引用值与运行时常量池中的引用值一致。
关于上面的代码,首先,在堆中会有一个"abc" 实例,全局String PooI中存放着"abc" 的一个引用值。在运行第二句的时候会生成两个实例,一个是"def"的实例对象,并且在String Pool中存储一个"def" 的引用值,还有一个是new出来的一个 “def” 的实例对象,与上面那个是不同的实例。在解析s3时查找String Pool,里面有"abc"的全局驻留字符串引用,所以s3的引用地址与之前的那个已经存在的相同。s4是在运行的时候调用intern()函数,返回String Pool中"def" 的引用值,如果没有就将s2的引用值添加进去。在这里,String Pool中已经有"def"的引用值了,所以返回上面在new s2的时候添加到String Pool中的"def" 引用值。最后,s5在解析时就也是指向存在于String Pool中的"def" 的引用值。
Java面向对象编程进阶--其他_第6张图片
这是我自己画的图,乱七八糟的,了解的不全面所以应该是有地方不对的吧(欢迎批评指正)

String类中常用的方法

关于常用的方法可以自行百度吧,用着用着就会了(滑稽)。

设计模式简要了解

开闭原则
指的是让设计的系统对扩展开放,对修改封闭

  • 对扩展开放是指应对需求变化要灵活,在新增功能时不需要修改已有的代码,增加新代码即可
  • 对修改封闭是指核心部分经过精心设计后,不再因为需求变化而变化

在实际开发中,虽然无法完全做到,但要尽量遵守开闭原则。

你可能感兴趣的:(Java学习笔记)