首页 > 编程语言 >Java面向对象知识全解(OOP)

Java面向对象知识全解(OOP)

时间:2024-09-12 16:49:43浏览次数:3  
标签:Java name System OOP println 全解 方法 public String

类是抽象的,概念的;对象是具体的,实际的;类说对象的模板,对象是类的一个个体

属性

属性的定义语法同变量:访问修饰符 属性类型 属性名

属性的定义类型可以是任意类型,包含基本类型或引用类型

属性如果不赋值,有默认值,规则和数组一样

创建对象方法

先声明再创建

Cat cat;

cat = new Cat()

直接创建

Cat cat = new Cat()

Java内存分析

栈:一般存放基本数据类型(局部变量)

堆:存放对象

方法区:常量池(常量,字符串),类加载信息

方法重载

java中允许同一个类中,多个同名方法存在,但要求形参列表不一致

方法名:必须相同

形参列表:必须不同(参数类型或个数或顺序,至少有一样不同,参数名无要求)

返回类型:无要求

可变参数

java允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法

语法:访问修饰符 返回类型 方法名(数据类型... 形参名){ }

【基本使用】

//1. int... 表示接收的是可变参数,类型为int,即可以接收多个int(0个或多个)
//2.使用可变参数时,可以当作数组来使用 即nums可以当作数组
public int sum(int... nums){
    System.out.println(nums.length);
    return 0;
}

可变参数的实参可以为0个或任意多个

可变参数的实参可以为数组

可变参数的本质就是数组

可变参数可以和普通类型的参数一起放在形参列表,但必须爆炸可变参数在最后

一个形参列表中只能出现一个可变参数

构造方法/构造器

构造方法又叫构造器,是类的一种特殊的方法,它的主要作用就是完成对新对象的初始化

语法:[修饰符] 方法名(形参列表){

方法体

}

构造器的修饰符可以默认

构造器没有返回值

方法名和类名必须相同

构造器的调用由系统完成

一个类可以定义多个构造器,即构造器重载

构造器是完成对象的初始化,并不是创建对象

在创建对象时,系统自动调用该类的构造方法

如果程序员没有定义构造方法,系统会自动给类生成一个默认无参构造方法

一旦定义了自己的构造器,默认的构造器就覆盖了,就不能再使用默认的无参构造器,除非显式的定义无参构造器

this

java虚拟机给每个对象分配this,代表当前对象。

简单来说,哪个对象调用,this就代表哪个对象

this关键字可以用来访问本类的属性,方法,构造器

this用于区分当前类的属性和局部变量

访问成员方法的语法:this.方法名(参数列表)

访问构造器语法: this(参数列表):注意只能再构造器中使用

this不能在类定义的外部使用,只能在类定义的方法中使用

访问修饰符

java提供四种访问修饰符,用于控制方法和属性(成员变量)的访问权限:

public

公开级别,对外公开

protected

对子类和同一个包中的类公开

默认级别

没有修饰符,向同一个包的类公开

private

只有本类可以访问,不对外公开

修饰符可以同来修饰类中的属性,成员方法和类

只有默认和public可以修饰类

封装

封装就是把抽象出来的数据【属性】和对谁家的操作【方法】封装在一起,数据被保护在内部,程序的其它部分只有通过授权的操作【方法】才能对数据进行操作

封装的实现步骤

将属性进行私有化

提供一个公共的set和get方法

继承

继承可以解决代码复用,让我们的编程更加接近人类思维,当多个类存在相同的属性和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可。

继承的基本语法

class 子类 extends 父类{

}

子类会自动拥有父类定义的属性和方法

注意细节:

1,子类继承了所有的属性和方法,但私有属性不能在子类中直接访问,要通过公共的方法取访问

2,子类必须调用父类的构造器,完成父类的初始化

3,当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中使用supper去指定父类的哪个构造器完成对父类的初始化工作,否则,编译不通过

4,如果希望指定去调用父类的某个构造器,则显示的调用一下

5,super在使用时,需要放在构造器第一行(super只能在构造器中使用)

6,super()和this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器

7,java所有类都是Object的子类,Object是所有类的基类

8,父类构造器的调用不限于直接父类,将一直往上追溯到Object类(顶级父类)

9,子类最多只能继承一个父类,即java的单继承机制

10,不能滥用继承,子类和父类之间必须满足is-a的逻辑关系

11,如果子类和父类有相 同的属性时,访问子类这个属性,会优先查看子类这个属性是否可以访问,如果可以,则返回子类的这个属性,否则,就去访问父类的这个属性。

super

super代表父类的引用,用于访问父类的属性,方法,构造器

访问父类的属性和方法,但不访问私有的

访问父类的构造器:super(参数列表);参数列表对于不同的构造器,只能放在子类构造器的第一句,只能出现一句

super给编程带来的便利

1,调用父类构造器的好处:分工明确,父类属性由父类初始化,子类属性由子类初始化

2,当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。用法:super.方法名()

3,super的访问不限于直接父类,如果父类的父类和本类有同名的成员,也可以使用super去访问父类的父类的成员;如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则。(遵守访问权限规则)

方法重写/覆盖

方法的重写就是子类有一个方法,和父类的某个方法的名称,返回值,参数一样,那么我们就说这个子类的这个方法重写/覆盖了父类的方法

细节

1,子类方法的返回类型和父类方法的返回类型一样,或者是父类返回类型的子类。

2,子类方法不能缩小父类方法的访问权限

多态

基本介绍

方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承的基础之上的

对象的多态(核心)

一个对象的编译类型和运行类型不一致

编译类型在定义对象时,就确定了,不能改变

运行类型是可以变化的

编译类型看定义时“=”的左边,运行类型看 “=”的右边

多态的向上转型

本质:父类的引用指向了子类的对象

语法:父类类型 引用名 = new 子类类型();

特点:编译类型看左边,运行类型看右边;可以调用父类的所有成员(须遵守访问权限),不能调用子类中 的特有成员;最终运行效果看子类的具体表现

【测试环境】

package java_fundation.super_;
​
public class Animal {
    String name = "动物";
    int age = 18;
    public void sleep(){
        System.out.println("睡");
    }
    public void eat(){
        System.out.println("吃");
    }
    public void run(){
        System.out.println("跑");
    }
    public void show(){
        System.out.println("hello,你好");
    }
}
package java_fundation.super_;
​
public class Cat extends Animal {
    public void eat(){
        System.out.println("猫吃鱼");
    }
    public void catchMouser(){
        System.out.println("猫抓老鼠");
    }
}

【测试类】

package java_fundation.super_;
​
public class Client {
    public static void main(String[] args) {
        //向上转型
        Animal animal = new Cat();
        //也符合语法
        Object object = new Cat();
        //不能调用子类特有的成员
        //animal.catchMouser();
        /*
        在编译阶段,能调用哪些成员,是由编译类型决定的
        最终运行结构看子类的具体表现,即调用方法时,按照从子类开始查找方法,然后调用
         */
        animal.eat();//猫吃鱼
        animal.run();//跑
    }
}

多态的向下转型

语法 :子类类型 引用名 = (子类类型)父类引用;

只能强转父类的引用,不能强转父类的对象

要求父类的引用必须指向的是当前目标类型的对象

可以调用子类类型中所有的成员

【测试环境】

新增Dog类

​package java_fundation.super_; ​
public class Dog extends Animal{ }

【测试类】

package java_fundation.super_;
​
public class Client {
    public static void main(String[] args) {
        Animal animal = new Cat();
        //向下转型
        Cat cat = (Cat)animal;
        cat.catchMouser();
        //要求父类的引用必须指向的是当前目标类型的对象
        Dog dag = (Dog)animal;//报错
    }
}

属性重写问题

属性没有重写之说,属性的值看编译类型

instanceof比较操作符

用于判断对象的运行类型是否为XX类型或XX类型的子类型

【测试类】

package java_fundation.super_;
​
public class Client {
    public static void main(String[] args) {
        Cat cat = new Cat();
        System.out.println(cat instanceof Cat);//true
        System.out.println(cat instanceof Animal);//false
        Animal animal = new Cat();
        System.out.println(animal instanceof Cat);//true
        System.out.println(animal instanceof Animal);//true
    }
}

动态绑定机制【重要】

1,当调用对象方法时,该方法会和该对象的内存地址/运行类型绑定

2,当调用对象属性时,没有动态绑定属性,哪里声明,哪里使用

【测试环境】

package java_fundation.poly_dynamic;
​
public class A {
    public int i;
    public int sum(){
        return getI()+10;
    }
    public int sum1(){
        return i+10;
    }
    public int getI(){
        return i;
    }
}
package java_fundation.poly_dynamic;

public class B extends A{
    public int i =20;
    public int sum(){
        return i+20;
    }
    public int getI(){
        return i;
    }
    public int sum1(){
        return i + 10;
    }
}

【测试类】

package java_fundation.poly_dynamic;

public class Test {
    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.sum());//调用B类的方法和属性,结果为40
        System.out.println(a.sum1());//调用B类的方法和属性,就跟为30
    }
}

当注释掉B类的sum和sum1方法后

package java_fundation.poly_dynamic;

public class B extends A{
    public int i =20;
//    public int sum(){
//        return i+20;
//    }
    public int getI(){
        return i;
    }
//    public int sum1(){
//        return i + 10;
//    }
}

测试类结果

package java_fundation.poly_dynamic;

public class Test {
    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.sum());//调用A类的sum方法,然后调用B类的getI方法,结果为30
        System.out.println(a.sum1());//调用A类的sum1方法,结果为20
    }
}

多态数组

数组的定义类型为父类类型,里面保存的实际元素类型为子类类型

多态参数

方法定义的形参类型为父类类型,实参类型为子类类型

Object类详解

类object是类层次结构的根类。每个类都使用object作为超类。所有对象(包括数组)都实现这个类的方法

equlas方法

“==”和equlas的对比

1,==:既可以判断基本类型,又可以判读引用类型

2,==:如果判断基本类型,判断的是值是否相等。

3,==:如果判断的是引用类型,判断的是地址是否相等,即判断是不是同一个对象

4,equlas:是Object类中的方法,只能判断引用类型

5,默认判断的是地址是否相等,子类往往可以重写该方法,用于判断内容是否相等。比如Integer,String。

自定义重写equlas方法

判断对象的属性是否相同

package java_fundation.obiect_;

public class EqualsExercise01 {
    public static void main(String[] args) {
        Person person1 = new Person("jack", 10, '男');
        Person person2 = new Person("jack", 10, '男');
        Person person3 = new Person("Tom", 11, '女');
        System.out.println(person1.equals(person2));//true
        System.out.println(person1.equals(person3));//false
        Person person4 = person1;
        System.out.println(person1.equals(person4));//true
    }
}
class Person {
    private String name;
    private int age;
    private char gender;
    public Person(String name, int age, char gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }
    //重写object的equals方法
   public boolean equals(Object obj) {
        //判断如果比较的两个对象是同一个对象,则直接返回true
        if(this == obj){
            return true;
        }
        //类型判断
        if(obj instanceof Person){
            //类型转化
            Person person = (Person)obj;
            return this.name.equals(person.getName()) && this.age == person.getAge() && this.gender == person.getGender();
        }
        return false;
    }
}

hashCode方法

返回该对象的哈希码值,支持此方法是为了提高哈希表的性能

1,提高哈希结构的容器的效率

2,两个引用,如果指向的是同一个对象,则哈希值肯定一样

3,两个引用,如果指向的是不同对象,则哈希值不一样

4,哈希值主要是根据地址号来的,不能将哈希值等价于地址

toString方法

基本介绍

默认返回:全类名+@+哈希值的十六进制(jdk源码)

子类往往重写toString方法,用于返回对象的属性信息

如对以上的Person类重写toString方法

@Override
public String toString() {
    return "Person{" +
            "name='" + name + '\'' +
            ", age=" + age +
            ", gender=" + gender +
            '}';
}

当我们直接输出一个对象时,toString方法会被默认的调用

finalize方法

在实际开发中,几乎不会去运用

1,当对象被回收,系统自动调用该对象的finalize方法。子类可以重写给方法,做一些释放资源的操作

2,什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁对象,在销毁该对象,会先调用finalize方法。

3,垃圾回收机制的调用,是由系统决定,也可以通过System.gc()主动触发垃圾回收机制。

package java_fundation.obiect_;

public class Finalize_ {
    public static void main(String[] args) {
        Car car = new Car("宝马");
        car = null;//这时对象空间就是一个垃圾,垃圾回收器就会回收(销毁)对象,在销毁对象前,会调用该对象的finalize方法
        //可以在这个方法中写入自己的业务逻辑代码,比如释放资源,数据库的连接,或者打开文件
        //如果不重写finalize方法,就会调用Object类的finalize方法,即默认处理

        //主动调用垃圾回收器
        System.gc();
        System.out.println("程序退出");
    }
}
class Car{
    private String name;
    public Car(String name){
        this.name = name;
    }
    //重写finalize方法
    @Override
    protected void finalize() throws Throwable {
        System.out.println("销毁汽车"+name);
    }
}

静态变量(类变量)

static变量是同一个类所有对象共享的;

static变量在类加载的时候就生成了;

什么是类变量

类变量也就静态变量/静态属性,是该类的所有对象共享的变量,是任何一个该类的对象去访问它时,取得的都是相同的值,统统该类的对象去修改它时,修改的也是同一个变量

如何定义类变量

定义语句:

访问修饰符 static 数据类型 变量名

如何访问类变量

类名.类变量名

对象.类变量名

类方法

基本介绍

类方法也就静态方法

访问修饰符 static 数据返回类型 方法名(){ }

在类加载时就生成了

类方法的调用

使用方法:类名.类方法名或者 对象.类方法名

注意点

1,类方法中不允许是有和对象有关的关键字,比如this和super

2,类方法(静态方法)中只能访问静态变量或静态方法

3,普通成员方法,可以访问静态成员和非静态成员

main语法说明

1,java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public

2,java虚拟机在执行main()方法时不必创建对象,所以该方法必须时static

3,该方法接收String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数

特别提示

1,在mian()方法中,我们可以直接调用main方法所在类的静态方法或静态属性

2,但是,不能直接调用该类的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员

代码块

代码块又称为初始代码块,属于类中的成员【即是类的一部分】,类似于方法,将逻辑语句封装在方法体中,通过{}包围起来

但和方法不同,没有方法名,没有返回,没有参数,只要方法体,而且不用通过对象或类显示调用,而是在类加载时,或创建对象时隐式调用。

基本语法

[修饰符]{
​
};

修饰符可选写,要写的话,只能写static

代码块分为两类,使用static修饰的叫静态代码块,没有static修饰的,叫普通代码块

逻辑语句可以为任何逻辑语句

作用

相当于另外一种形式的构造器(对构造器的补充机制),可以初始化操作

如果多个构造器中有重复语句,可以抽取到初始代码块中

代码块调用的顺序优先于构造器

package java_fundation.codeblock_;
​
public class CodeBlock01 {
    public static void main(String[] args) {
        Movie movie = new Movie("终结者");
​
    }
​
}
class Movie{
    private String name;
    private String price;
    private String director;
​
    {
        System.out.println("电影开始了");
        System.out.println("广告开始播放");
    }
​
    public Movie(String name) {
        System.out.println("Movie(String name)被调用");
        this.name = name;
    }
​
    public Movie(String name, String price) {
        this.name = name;
        this.price = price;
    }
​
    public Movie(String name, String price, String director) {
        this.name = name;
        this.price = price;
        this.director = director;
    }
}

代码块使用细节

1,static代码块也叫静态代码块,作用是对类进行初始化,而且它随着类的加载而执行,并且只执行一次。如果是普通代码块【没有被static修饰的代码块】,每创建一个对象,就执行一次

2,类什么时候被加载

创建对象实例时(new)

创建子类对象实例时,父类也会被加载

使用类的静态成员时

3,普通代码块,在创建对象实例时,会被隐式的调用。每创建一次,就会调用一次。如果使用类的静态成员,普通代码块并不会执行

4,创建一个对象时,在一个类调用的顺序

①调用静态代码块的静态属性初始化(静态代码和静态属性初始化调用优先级一样,如果有多个静态代码块和多个静态属性变量初始化,则按照他们定义的顺序执行)

②调用普通代码块和普通属性的初始化(普通代码块和普通属性初始化的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按照定义顺序执行)

③调用构造方法

package java_fundation.codeblock_;
​
public class CodeBlock02 {
    public static void main(String[] args) {
        A a = new A();
​
    }
}
​
class A{
    private int n2 = getN2();
    {
        System.out.println("A 普通代码块01");
    }
    //静态属性
    private static  int n1 = getN1();
    static {
        System.out.println("A 静态代码块01");
    }
    public static int getN1(){
        System.out.println("getN1 被调用");
        return 100;
    }
    public int getN2(){
        System.out.println("getN2被调用");
        return 200;
    }
​
    public A() {
        System.out.println("A 无参构造器");
    }
}
​
/*
输出结果
getN1 被调用
A 静态代码块01
getN2被调用
A 普通代码块01
A 无参构造器
 */

5,构造器的最前面隐含了super()和调用普通代码块。静态相关的代码块,属性初始化,在类加载时,就执行完毕,因此是优先于构造器和普通代码块执行的。

6,创建子类时的调用顺序

①父类的静态代码块和静态属性

②子类的静态代码块和静态属性

③父类的普通代码块和普通属性初始化

④父类的构造方法

⑤子类的普通代码块和普通属性初始化

⑥子类的构造方法

7,静态代码块只能调用静态成员,普通代码块可以调用任意成员

单例模式

所谓单例模式,就是采用一定的方式保证在整个软件系统中,对某个类只能存在一个实例,并且该类只提供一个取得其对象实例的方法

饿汉式

无论是否使用,在类加载时就会创建实例

①构造器私有化

②类的内部静态创建对象

③向外暴露一个静态的公共方法

package java_fundation.single_;
//饿汉式
public class Single01 {
    public static void main(String[] args) {
        GirlFriend instance = GirlFriend.getInstance();
        System.out.println(instance);
        GirlFriend instance2 = GirlFriend.getInstance();
        System.out.println(instance2 == instance);//true
    }
}
class GirlFriend{
    private String name;
    //在类内部创建对象
    private static GirlFriend gf = new GirlFriend("小红");
    //构造器私有化
    private GirlFriend(String name){
        this.name = name;
    }
    //提供一个公共的static方法,返回gf对象
    public static GirlFriend getInstance(){
        return gf;
    }
    @Override
    public String toString() {
        return "GirlFriend{" +
                "name='" + name + '\'' +
                '}';
    }
}

懒汉式

只有在使用时才会创建这个实例

①构造器私有化

②类的内部创建对象

③向外暴露一个静态的公共方法

package java_fundation.single_;
​
public class GirlFriend02 {
    public static void main(String[] args) {
        Cat cat = Cat.getCat();
        System.out.println(cat);
        Cat cat1 = Cat.getCat();
        System.out.println(cat1);
        System.out.println(cat1 == cat);//true
    }
}
class Cat{
    private String name;
    private static int age = 18;
    //先在类的内部声明
    private static Cat cat;//默认为空
    //构造器私有化
    private Cat(String name){
        this.name = name;
        System.out.println("构造器被调用");
    }
    //向外提供一个静态的公共方法
    public static Cat getCat(){
        if(cat == null){
            cat = new Cat("小猫娘");
        }
        return cat;
    }
​
    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                '}';
    }
}
/*
输出结果
构造器被调用
Cat{name='小猫娘'}
Cat{name='小猫娘'}
true
 */

小结

1,二者最主要的区别在于创建对象的时间不同:饿汉式在类加载就创建了对象实例,而懒汉式在使用时才创建

2,饿汉式不存在线程安全问题,懒汉式存在线程安全问题

3,饿汉式存在资源浪费

final关键字

基本结束

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

1,被final修饰的类,不可以被继承

2,被final修饰的方法,不可以被重写/覆盖

3,被final修饰的属性,不可以被修改

使用细节

1,final修饰的属性又叫床两,一般用 xx_xx_xx来命名

2,final修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以在如下位置之一

①定义时

②构造器中

③代码块中

3,如果final修饰的属性是静态的,则初始化的位置只能是

①定义时

②在静态代码块中,不能在构造器中赋值

4,final修饰不能继承,但是可以实例化对象

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

5,一般来说,如果一个类已经是final类了,就没必要再将方法修饰为final方法

6,final不能修饰构造器

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

8,包装类(Integer,Doubl,Float,Boolean等都是final)String也是final类

transient关键字

总的来说:transient修饰的关键字不会被序列化

  1. 一旦变量被transient修饰,变量不再是对象持久化的一部分,该变量在反序列化后也无法获得

  2. transient关键字只能修饰变量,不能修饰方法和类

  3. 一个静态变量不管是否被transient修饰,均不能被序列化

抽象类(abstract)

用abstract关键字修饰的类叫做抽象类

用abstract关键字修饰的方法叫做抽象方法,抽象方法不能有方法体

当一个类中存在抽象方法时,需要将带类声明为abstract

一般来说,抽象类会被继承,由它的子类来实现抽象方法

使用细节

1,抽象类不能被实例化

2,一旦类包含了abstract方法,则这个类必须声明为anstract类

3,抽象类不一定要包含抽象方法,也就是说,抽象类可以没有abstract方法。

4,abstract只能修饰类和方法。

5,抽象类可以有任何成员,包括构造器,静态属性等

6,抽象方法不能有方法体

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

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

接口(interface)

基本介绍

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

在jdk7.0前,接口里所有方法都没有方法体,即都是抽象方法。

在jdk8.0后,接口可以有静态方法,默认方法(必须使用default关键字修饰),也就是说接口可以有方法的具体实现

使用细节

1,接口不能被实例化

2,接口中的所有方法是public方法,接口中的抽象方法,可以没有abstract修饰

3,一个普通类实现接口,就必须将该接口中的所有方法都实现

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

5,一个类可以同时实现多个接口

6,接口中的属性,只能是final的,而且是public static final 修饰符,必须初始化,比如int a = 1;实际上是public static final final int a = 1;

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

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

9,接口的修饰符,只能是public和默认

接口和继承

接口和继承解决的问题不同

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

接口的价值在于:设计,设计好各种规范(方法),让其它类去实现这些方法

接口比继承更加灵活

接口时满足is-a的关系,继承是只需要满足like-a的关系

接口在一定程度上实现代码解耦

接口多态特性

接口类型的变量可以指向实现了接口类的对象实例

多态参数

多态数组

接口的多态传递

package java_fundation.interface_;
​
public class InterfacePoly {
    public static void main(String[] args) {
        Interface2 interface2 = new Test();
​
        //如果Interface2继承了interface1接口,而Test类实现了Interface2接口
        //就相当于Test类也实现了Interface1接口
        Interface1 interface1 = new Test();
    }
}
interface Interface1 {
    void hi();
}
interface Interface2 extends Interface1 {
    void hello();
​
}
class Test implements Interface2 {
    @Override
    public void hello() {
    }
    @Override
    public void hi() {
    }
}
​

内部类

基本介绍

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

基本语法

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

内部类的分类

定义在外部类局部位置上(比如方法内):

局部内部类(有类名)

匿名内部类(没有类名)

定义在外部类的成员位置上:

成员内部类(没用static修饰)

静态内部类(使用static修饰)

局部内部类

说明

局部内部类是定义在外部类的局部位置上,比如方法或代码块中,并且有类名,本质任然是一个类

使用细节

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

2,不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量可以使用final修饰。

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

4,局部内部类访问外部类的成员

访问方式:直接访问

5,外部类访问局部内部类的成员

访问方式:创建对象,再访问(注意:必须在作用域内)

6,如果外部类和局部内部类的成员重名,默认就近原则,如果想访问外部类的成员,则可以使用(外部类.this.成员)

外部类.this本质就是外部类的对象,即哪个对象调用了方法或属性,外部类.this就是哪个对象

7,外部其他类不能访问局部内部类(因为局部内部类是一个局部变量)

【测试】

package java_fundation.innerclass;
​
public class LocalInnerClass {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.m1();
    }
}
class Outer{//外部类
    private int n1 = 100;
    private void m2(){}
    public void m1(){
        //局部内部类是定义在外部类的局部位置上,通常是在方法
        class Inner{//局部内部类(本质任然是一个类)
            private int n1 = 800;
            public void f1(){
                //可以直接访问外部类的所有成员,包括私有的
                //遵守就近原则,调用Inner局部内部类的n1
                System.out.println("n1=" + n1);
                //访问外部类成员(和内部类重名的成员)
                System.out.println("外部类的n1=" + Outer.this.n1);
                m2();
            }
        }
        //外部类访问局部内部类的成员
        Inner inner = new Inner();
        inner.f1();
    }
}

匿名内部类【重要】

说明

匿名内部类是定义在外部类的局部位置上,比如方法,并且没有类名本质还是类同时还是一个对象

基本语法

new 类或接口(参数列表){
    类体
}

【测试】

package java_fundation.innerclass;
​
public class AnonymousInnerClass {
    public static void main(String[] args) {
        Outer02 outer02 = new Outer02();
        outer02.method();
    }
}
class Outer02{
    private int n1 = 10;
    public void method(){
        //编译类型是A
        //运行类型就是匿名内部类
        /*
        底层会分配类名 Outer02$1
        class Outer02$1 implements A{
            @Override
            public void cry() {
                System.out.println("老虎在叫");
            }
        }
         */
        //jdk底层在创建匿名内部类Outer02$1,立即马上就创建了Outer02$1的实例,并且把地址返回给tiger
       A tiger = new A(){
            @Override
            public void cry() {
                System.out.println("老虎在叫");
            }
        };
       tiger.cry();
       System.out.println("tiger的运行类型=" + tiger.getClass());
        //基于类的匿名内部类
        //编译类型 Father
        //运行类型 Outer02$2
       Father father = new Father("jack"){
            @Override
           public void test(){
                System.out.println("匿名内部类重写test方法");
            }
        };
        System.out.println("father对象的运行类型" + father.getClass());
        //抽象类的匿名内部类
        Animal animal = new Animal(){
​
            @Override
            void eat() {
                System.out.println("小马在吃草");
            }
        };
        animal.eat();
    }
}
interface A{
    public void cry();
}
class Father{
    public Father(String name){
​
    }
    public void test(){
​
    }
​
}
abstract class Animal{
    abstract void eat();
}
​
/*
输出结果
老虎在叫
tiger的运行类型=class java_fundation.innerclass.Outer02$1
father对象的运行类型class java_fundation.innerclass.Outer02$2
小马在吃草
 */

使用细节

1,匿名内部类的语法比较,匿名内部类即是一个类的定义,也是一个一个对象,因此从语法上,它既有定义类的特征,也有创建类对象的特征。

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

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

4,作用域:仅仅在定义它的方法或代码块中

5,匿名内部类访问外部类成员:访问方式,直接访问

6,外部其它类不能访问匿名内部类

7,如果外部类和内部类的成员重名时,匿名内部类访问的话,默认就近原则,如果想访问外部类的成员,则可以使用(外部类.this.成员)访问

package java_fundation.innerclass;
​
public class AnonymousInnerClassDetail {
    public static void main(String[] args) {
        Outer03 outer03 = new Outer03();
        outer03.f1();
        System.out.println("main Outer03 hashcode" + outer03);
    }
}
class Outer03{
    private int x = 60;
    public void f1(){
        Person p = new Person(){
            //和外部类成员重名
            private int x = 99;
            @Override
            public void hi(){
                System.out.println("匿名内部类重写hi方法");
                System.out.println("访问匿名内部类的x=" + x);
                System.out.println("访问外部类的x=" + Outer03.this.x);
                System.out.println("Outer03.this hashcode" + Outer03.this);
​
            }
        };
        p.hi();//动态绑定,运行类型是Outer03
        //直接调用,匿名内部类直接返回的是一个对象·
        new Person(){
            @Override
            public void hi(){
                System.out.println("直接调用方法");
            }
        }.hi();
    }
}
class Person{
    public void hi(){
        System.out.println("Person hi()");
    }
}
/*
输出结果
匿名内部类重写hi方法
访问匿名内部类的x=99
访问外部类的x=60
Outer03.this hashcodejava_fundation.innerclass.Outer03@d716361
直接调用方法
main Outer03 hashcodejava_fundation.innerclass.Outer03@d716361
 */

成员内部类

说明

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

实现细节

1,可以直接访问外部类的所有成员

2,可以添加任意访问修饰符

3,作用域和其它外部类的成员一样,为整个类体

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

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

6,外部其它类访问成员内部类:两种方法

7,如果外部类和内部类的成员重名时,成员内部类访问的话,默认就近原则,如果想访问外部类的成员,则可以使用(外部类.this.成员)访问

【测试】

package java_fundation.innerclass;
​
public class MemberInnerClass {
    public static void main(String[] args) {
        Outer04 outer04 = new Outer04();
        outer04.test();
        //外部类访问成员内部类的两种种方式
        //第一种
        Outer04.Inner04 inner04 = outer04.new Inner04();
        //第二种 在外部类中,编写一个方法,返回Inner04内部类对象
        Outer04.Inner04 inner041 = outer04.getInner04();
​
    }
}
class Outer04{
    private int n1 = 10;
    public String name = "jake";
    class Inner04{//成员内部类
        public void say(){
            System.out.println("n1 = " + n1 + "name=" + name);
        }
    }
    public void test(){
        //使用内部类
        Inner04 inner04 = new Inner04();
        inner04.say();
    }
    //返回内部类的实例
    public Inner04 getInner04(){
        return new Inner04();
    }
}

静态内部类

说明

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

使用细节

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

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

3,作用域:同其他的成员一样,是整个类体

4,静态内部类访问外部类(静态成员):直接访问

5,外部类访问静态内部类:创建对象,再访问

6,外部其他类访问静态内部类:两种方式

7,如果外部类和内部类的成员重名时,静态内部类访问的话,默认就近原则,如果想访问外部类的成员,则可以使用(外部类.this.成员)访问

p
ackage java_fundation.innerclass;
​
public class StaticInnerClass {
    public static void main(String[] args) {
        Outer05 outer05 = new Outer05();
        outer05.show();
        //外部其他类访问静态内部类
        //方式一
        Outer05.Inner05 inner05 = new Outer05.Inner05();
        //第二种 在外部类中,编写一个方法,返回Inner05内部类对象
        Outer05.Inner05 instance = outer05.getInstance();
    }
}
class Outer05{
    private int  n1 = 10;
    private static String name = "Tom";
    static class Inner05{
        public void say(){
            System.out.println("name");
        }
    }
    public void show(){
        Inner05 inner05 = new Inner05();
        inner05.say();
    }
    public Inner05 getInstance(){
        return new Inner05();
    }
}

枚举类(enum)

枚举是一组常量的组合

可这样理解:枚举属于一种特殊的类,里面只包含一组有限的特定的对象

枚举有两钟实现方法:

①自定义枚举

②使用enum关键字实现枚举

自定义枚举

1,不需要提供set方法,因为枚举对象通常为只读

2,对枚举对象/属性使用final+static共同修饰,实现底层优化

3,枚举对象名通常使用全部大写,常量的命名规范

4,枚举对象根据需要,也可以有多个属性

package java_fundation.enum_;

/**
 * @author 子佩
 * @version 1.0
 */
public class Enumeration01 {
    public static void main(String[] args) {
        System.out.println(Season.SPRING);
    }
}

class Season{
    private String name;
    private String desc;
    //构造器私有化
    private Season(String name,String desc){
        this.name=name;
        this.desc=desc;
    }
    public static Season SPRING = new Season("春天","温暖");
    public static Season WINTER = new Season("冬天","凉爽");
    public static Season SUMMER = new Season("夏天","炎热");
    public static Season AUTUMN = new Season("秋天","凉爽");

    @Override
    public String toString() {
        return "Season{" +
                "name='" + name + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }
}

步骤

1,构造器私有化

2,本类内部创建一组对象

3,对外暴露对象(通过public final static修饰符)

4,可以提供get方法,但是不要提供set

使用enum关键字实现枚举

使用enum实现枚举,要求将定义常量对象,写在属性和构造器前面

如果有多个常量对象,用逗号间隔

package java_fundation.enum_;

/**
 * @author 子佩
 * @version 1.0
 */
public class Enumeration02 {
    public static void main(String[] args) {
        System.out.println(Season2.AUTUMN);
    }
}
enum Season2{

    SPRING("春天","温暖"),//自动调用构造器生成常量
    WINTER("冬天","凉爽"),
    SUMMER("夏天","炎热"),
    AUTUMN("秋天","凉爽"),
    WHAT;//自动调用无参构造器,可省略实参列表和小括号    
    private String name;
    private String desc;
    private Season2(String name, String desc){
        this.name = name;
        this.desc = desc;
    }
    
    private Season2(){

    }

    @Override
    public String toString() {
        return "Season2{" +
                "name='" + name + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }
}

使用细节

1,当我们使用enum关键字开发一个枚举类时,默认会继承Enum类

2,如果使用无参构造器创建枚举类,则实参类别和小括号可以省略

3,枚举对象必须放在枚举类的首行

常用方法

package java_fundation.enum_;

/**
 * @author 子佩
 * @version 1.0
 */
public class EnumMethod {
    public static void main(String[] args) {
        Season2 summer = Season2.SUMMER;

        //name方法
        System.out.println(summer.name());

        //ordinal方法,输出该枚举对象的次序/编号
        System.out.println(summer.ordinal());

        //从反编译可以看出 values方法,返回 Season3[]
        //含有定义的所有枚举对象
        Season3[] values = Season3.values();
        for (Season3 season : values) {
            System.out.println(season);
        }

        System.out.println("=====valueOF=====");
        //valueOf方法:将字符串转换成枚举类型,要求字符串必须是已有的常量名
        Season3 summer1 = Season3.valueOf("SUMMER");//与上面的summer对象相等
        System.out.println(summer1);

        //compareTo方法:比较两个枚举常量,比较的就是编号
        //Season3.SPRING编号-Season3.AUTUMN编号
        System.out.println(Season3.SPRING.compareTo(Season3.AUTUMN));//-3
    }
}

enum Season3{

    SPRING("春天","温暖"),
    WINTER("冬天","凉爽"),
    SUMMER("夏天","炎热"),
    AUTUMN("秋天","凉爽");
    private String name;
    private String desc;

    private Season3(String name, String desc){
        this.name = name;
        this.desc = desc;
    }
    @Override
    public String toString() {
        return "Season2{" +
                "name='" + name + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }
}
/*
输出结果
SUMMER
2
Season2{name='春天', desc='温暖'}
Season2{name='冬天', desc='凉爽'}
Season2{name='夏天', desc='炎热'}
Season2{name='秋天', desc='凉爽'}
Season2{name='null', desc='null'}
=====valueOF=====
Season2{name='夏天', desc='炎热'}
-3
*/

enum实现接口

1,使用enum关键字后,就不能再继承其它类了,因为enum会隐式继承Enum类

2,枚举类和普通类一样,可以实现接口

注解(Annotation)

注解的理解

1,注解也被称为元数据,用于修饰解释器 包,类,方法,属性,构造器,局部变量等数据信息

2,和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在程序中的补充信息

3,在javaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在javaEE中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替javaEE旧版中所遗留的繁杂代码和xml配置等

三个基本的注解

1,@Override

限定某个方法,是重写父类的方法,该注解只能用于方法

2,@Deprecated

用于表示某个程序元素已过时。即不推荐使用,但是任然可以使用

可以做到新旧版本的兼容和过渡

3,@SuppressWarning

抑制编译器警告

四种元注解

元注解的介绍

JDK的元注解用于修饰其它的注解

@Retention

指定注解的作用范围,三种:SOURCE,CLASS,RUNTIME

@Target

指定注解可以在哪些地方使用

@Documented

指定该注解是否会在javadoc体现

@Inherited

子类会继承父类注解

标签:Java,name,System,OOP,println,全解,方法,public,String
From: https://blog.csdn.net/zi_pei/article/details/142171268

相关文章

  • 基于javaC语言试题生成与考试系统的计算机毕设
    C语言试题生成与考试系统摘 要当前,网络教学方兴未艾。网上考试已在其中扮演了重要的角色,传统试卷考试方式有待提高。网络教学已从其规范性、科学性及考试工作组织、管理的统一性,影响到教学质量的好坏。基于此,本系统开发实现了基于B/S模式的c试题生成与考试系统,其中数据库采用MYSQ......
  • Java学习1:命令行窗口执行.java程序(自用)
    编写源代码:编译与执行:1、普通方法:生成了.class文件(字节码)2、从Java11开始,由单个文件构成的java程序,无需编译,可以直接执行。使用这种方法也不产生.class文件。该方法可快速测试程序。但源文件必须是单个的.java文件。问题:文件名与public类名是否必须相同?答:不一定......
  • 庖丁解java(一篇文章学java)
    (大家不用收藏这篇文章,因为这篇文章会经常更新,也就是删除后重发) 一篇文章学java,这是我滴一个执念...当然,真一篇文章就写完java基础,java架构,java业务实现,java业务扩展,根本不可能.所以,这篇文章,就是一个索引,索什么呢?   请看下文.关于决定开始写博文的介绍......
  • java社招面试题(亲身经历8w字,持续更新中)
    1.1pom文件的常见标签<groupId>:定义项目的组ID,通常是组织的域名倒写,如 com.example。<artifactId>:定义项目的工件ID,是项目的唯一标识符。<version>:定义项目的版本号,如 1.0.0。<packaging>:指定项目的打包类型,如 jar、war 等,默认为 jar。<dependencyManagem......
  • JavaSE:2、基本数据类型
    1、整数类型在Java中,整数类型包括以下几个:byte字节型(8个bit,也就是1个字节)范围:-128~+127short短整形(16个bit,也就是2个字节)范围:-32768~+32767int整形(32个bit,也就是4个字节)最常用的类型:-2147483648~+2147483647long长整形(64个bit,也就是8个字节)范围:-9223372036854775808~......
  • 最强Java面试八股文总结,欢迎收藏!
    MySQL八股文 问:Mysql的存储引擎有理解过吗?我比较了解就是Innodb,myisam,Memory。 Innodb:现在的mysql默认存储引擎就是innodb,主要就是因为它是唯一一个支持事务的存储引擎,支持表级锁和行级锁,其索引的底层结构使用的是B+树,在数据,索引,表结构都存储到.idb中。 Myisam:其不支......
  • 2024年Java常见面试题整理
    1、java为什么要有包装类型?主要原因包括以下几点:处理基本数据类型的null值:基本数据类型(如int,double等)不能直接赋值为null,而包装类型(如Integer、Double)可以表示null值,这对于某些业务逻辑和数据处理来说非常有用。提供额外功能:包装类型提供了一些额外的方法和功能,这些......
  • Java突击面试八股文(15个技术栈,持续更新中)
    1.Java如何避免死锁注意加锁的顺序,保证每个线程按顺序进行加锁;加锁时限,可以设置一个超时时间;注意死锁检查,这是一种预防机制,可以确保发生死锁的第一时间进行处理。3、多线程(线程池)2线程有哪些状态(生命周期)新建、就绪、运行、阻塞、死亡3如何获取多线程的返回值?深坑!如果......
  • JavaScript开发技巧必备【一】
    1、使用Object.entries()和Object.fromEntries()//将对象转换为数组并转换回来,以便于操作constperson={name:'jack',age:20};constentries=Object.entries(person);//[['name','jack'],['age',20]]constnewPerson=Object.fromEn......
  • java+opencv4来获取图像中轮廓的最小外接矩形
     举例:获取以下图片中的火车的最小外接矩形完成钱确认opencv的环境配置完整。要想查找图片中的轮廓信息,首先要获取图片的二制图,因为二制图的查找效率更高,具体原因自行百度。为了提高转换二制图的效率可以现将图片转换为灰度图。示例代码如下://将彩色图像转换为灰度图像M......