面向对象(高级)

news2025/1/22 15:55:01

目录

1. 类变量和类方法(静态变量)

类变量(静态变量)

内存刨析:

注意事项和使用细节:

 类方法(静态方法): 

使用场景:

注意事项和细节讨论:

2. main方法中的语法

3. 代码块

4. final关键字

5. 内部类

1. 局部内部

2. 匿名内部类

匿名内部类的使用细节:

实例内部类

静态内部类


每个人都可以活得更精彩,不要让惰性毁了你,坚持学习。

随着我们对面向对象的不断了解,我们已经学过很多语法和思想了,虽然不是很好理解,但是也没有难到令人放弃,随着不断地练习,总有一天自己会瞬间通透的;更难学的还在后面。不要觉得Java很难,多给自己点信心,加油。

那好,聊到这里我们继续学习更难的知识点。

1. 类变量和类方法(静态变量)

类变量(静态变量)

引出: 假设有一群小孩在堆雪人,不断地有小孩要加入;问;某个时刻共有多少个小孩?

思路: main中定义count,每个小孩加入后count++。

问题分析: count是个独立对象,访问起来很麻烦,并且没有用到面向对象(OOP)

问题解决: 在类中引入一个类变量(静态变量)static修饰 ,该变量最大的特点就是被该程序中的所有对象共有。

例如:

public class demo {
    public static void main(String[] args) {
        new Child("小明");
         new Child("小红");
        System.out.println(Child.count);
    }
}
class Child {
    private String name;
    public static int count = 0;

    public Child(String name) {
        this.name = name;
        count++;
    }
}

图示:

内存刨析:

随着版本的不同,静态变量存放的位置不同。

有的书是这样得:

 而有的书是说,static得信息存在静态域中:

无论放在哪里,对我们的使用并不影响。

注意事项和使用细节:

🐤  何时使用:需要所有对象共享一个变量

🐤  类变量和实例变量(普通变量)的区别:

类变量是该类所有对象所共享对的,而实例变量是个类对象独有的。

🐤  加上static成为类变量或静态变量,否则称之为实例对象、非静态变量或普通变量。

🐤  类变量的访问方式:

1. 在同一个类中访问:直接引用变量名即可

2. 在不同类中访问:必须通过类名.类变量名字;如:Child.count

原因:类变量是随着类的加载而加载的,所以在类的加载时就可以访问到类变量信息。

🐤  类变量的周期从类的开始到类的结束。

 类方法(静态方法): 

语法形式:

访问修饰符        static        返回类型        方法名() {     }   (推荐)      或者

static        访问修饰符        返回类型        方法名() {     }   (不推荐)

调用:

语法:类名.方法名 或者 对象名.方法名 (前提是满足访问修饰符的访问权限和范围)

注意:

非静态的可以调用静态的,但静态的只能调用静态的不可以调用非静态的。

在程序运行时,类先加载,静态此时也就加载,在对象创建后才有了非静态;所以时先有静态后有非静态。

使用场景:

当方法不涉及到任何和对象相关的成员时,则可以将其设为静态方法,以便提升效率。

比如:工具类中的Utils、Math工具、Array类。

注意事项和细节讨论:

🐤 类方法和普通方法都是随着类的加载而加载的,将结构信息储存在方法区:

类方法中无this的参数

而普通方法隐藏着this的参数

🐤类方法可以通过类名调用,也可以通过方法名调用

🐤普通方法和对象有关,需要通过对象名调用,比如:对象名.方法名(参数)【dog.eat()】 不能通过类名调用

例如:

class Dog {
    public void say()  {
        //非静态
    }
    public static void hi(){
        //静态
    }
}
public class demo {
    public static void main(String[] args) {
        Dog.hi();
        Dog.say();//报错
    }
}

🐤 类方法中不允许使用与对象有关的关键字,例如:this和super

🐤 类方法只能访问静态变量或静态方法,而普通成员中既可以访问静态也可以访问非静态

总结:静态可以访问静态的,非静态可以访问静态和非静态的。

2. main方法中的语法

深入理解main方法

1. mian方法被Java虚拟机调用

2. Java虚拟机调用main方法访问权限必须是public

3. Java虚拟机在执行main方法时不需要创建对象,所以i方法必须是static的

4.该方法接受String类型的数组传参,该数组中保存执行Java命令时传递所给类的参数:

也就是我们main方法中的这个:

String[] args  值是由执行程序时传进去的参数形成的一个数组。

例如:


public class Main {
    private static String name = "小明";
    private int age = 10;
    public static void main(String[] args) {
        System.out.println(name);
        hi();
        System.out.println(age);//错位,main中可以访问静态的,但是不可以访问非静态的
    }
    public static void hi() {
        System.out.println("hello");
    }
}


 提示: 

🐔: 在main方法中,我们可以直接调用main方法所在类的静态方法或静态属性

🐔: 但是,不能直接调用非静态的成员变量;想要调用,只能通过关键字 new 出实例对象,通过对象去访问。

如何在idea上实现main的动态传值:

由于我的是社区版的我就把b站老韩的视频链接放下来:

0384_韩顺平Java_main动态传值_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1fh411y7R8?p=385&vd_source=93857e709631270a9e771d5aaee79ecb

3. 代码块

基本介绍:代码块又称初始化块,属于类中的成员【即类的一部分】,类似于方法,讲语法封装在方法体中,用 { } 包围起来。

但和方法不同,无名,无参,无返回值,只是在类加载时,或创建对象时隐式调用。

语法:

修饰符{

        代码

};//“ ;”可写可不写

根据代码块定义的位置以及关键字,又可分为以下四种:
普通代码块
构造块
静态块
同步代码块(后续讲解多线程部分再谈)

🐔 普通代码块

此时的修饰符就是default默认不写;

{

        代码

}

🐔 静态代码块

此时的修饰符就是static

static{

        代码

}

🐔 构造块

定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量

使用场景:

如果多个构造器中都有重复的语句,可以抽取到初始化块中,提高代码的复用性。

举例:🌰

public class Student{
    private String name;
    private String gender;
    private int age;
    private double score;
    private static String classRoom;
    //实例代码块
    {
        this.name = "marry";
        this.age = 12;
        this.gender = "man";
        System.out.println(name+" is instance init()!");
    } 
    // 静态代码块
    static {
        classRoom = "303";
        System.out.println("I am static init()!");
    }
    // 构造代码块
    public Student(){
        System.out.println("I am Student init()!");
    }
    public static void main(String[] args) {
        Student s1 = new Student();
        Student s2 = new Student();
    }
}

从这个例子我们可以看出如下总结:

🐔创建对象时,会有如下顺序:

执行静态代码块 ——> 执行普通代码块 ——> 执行构造代码块

🐔 静态代码块仅执行一次,静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的

🐔如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次执行(合并)

🐔实例代码块只有在创建对象时才会执行

如果我们在此基础上加上继承,结构又会如何,执行顺序又会如何?

public class demo {
    public static void main(String[] args) {
         new Son();
    }
}
class Father {
    public Father() {
        System.out.println("我是父类的构造代码块");
    }

    {
        System.out.println("我是父类的代码块");
    }
    static{
        System.out.println("我是父类静态代码块");
    }
}
class Son extends Father{
    public Son() {
        System.out.println("我是子类的构造代码块");
    }
    {
        System.out.println("我是子类的代码块");
    }
    static{
        System.out.println("我是子类静态代码块");
    }
}

可以发现如下顺序:

 执行父类静态代码块 ——> 执行子类静态代码块 ——> 执行父类普通代码块 ——> 执行父类构造代码块——> 执行普通代码块 ——> 执行构造代码块

4. final关键字

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

使用到final关键字的情况:

🐔 当不希望类被继承:

final class A { } //无法被继承

🐔 当不希望父类的某个方法被子类重写时

🐔 当不希望某个类中某个值被修改

public  final int SIZE = 5 ;

🐔当不希望某个局部变量被修改

final double TAX_RATE = 0.08 ;

注意事项和使用细节:

1. final修饰的属性又叫常量,一般用 XX_XX_XX命名

2. final修饰的属性在定义时必须初始化,可选在如下位置:

(1)如:public  final int SIZE = 5 ;

(2)构造器中;

(3)在代码块中;

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

(1)定义时

(2)在静态代码块中,不能在构造器中赋值,因为实例对象才能调用构造器

4. final类不能被继承,但是可以实例化

5. final不能修饰构造方法

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

5. 内部类

内部类是本章的重难点,在以后看源码的时候,会看见大量的内部类。

基本介绍:当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么这个内部的完整结构最好使用内部类。在 Java 中,可以将一个类定义在另一个类或者一个方法的内部,前者称为内部类,后者称为外部类。内部类也是封装的一种体现。

基本语法:

 class OutClass { //外部类
    class InnerClass{ //内部类
    }
}

class other { //外部其他类

}

特点: 既可以访问私有属性,又可以体现类与类之间的包含关系。

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

(1)局部内部类(有类名)

(2)匿名内部类(没有类名)

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

(1)实例内部类(没有static)

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

1. 局部内部

说明:

1. 可以访问外部类的所有成员;

2. 不能添加访问修饰符,因为它的地位相当与局部变量,但是可以用final修饰

3. 作用域:仅仅只定义在它的方法或者代码段中

4. 在访问成员时直接调用即可

5. 外部类在方法中,可以创建内部类对象,然后调用方法即可;如:

public class Outer {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.n1();
    }
    private int n1 = 100;
    private void m2() {
        System.out.println("2");
    }
    public void n1() {
        final class Inner {
            public void f1() {
                System.out.println("1");
                m2();
            }
        }
        Inner inner = new Inner();
        inner.f1();
    }
}

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

2. 匿名内部类

本质:

(1)本质仍是一个类

(2)是个内部类

(3)从宏观上来来书评该类没有名字,但是在底层上被赋予了一个名字

(4)同时还是个对象

说明:匿名内部类定义在外部类的局部位置,譬如方法体,但是没有名字

语法:

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

        类体

};

例如:

class Outer {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.method();
    }
    private int m = 10;
    public void method() {
        //需求:使用一个IA接口,并创建一个对象
        //传统写法:写一个类,实现该接口
        IA tiger = new Tiger();
        tiger.cry();
    }
}
interface IA {
    public void cry();
}
class Tiger implements IA {
    @Override
    public void cry() {
       System.out.println("嗷嗷嗷嗷");
    }
}

 但是如果我只用一次,后面就不再使用,这里单独写一个Tiger时不时太浪费了,所以我们可以试着用匿名内部类写。


class Outer {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.method();
    }
    private int m = 10;
    public void method() {
        //需求:使用一个IA接口,并创建一个对象
        //传统写法:写一个类,实现该接口
        //现在我们不要Tiger类
       IA tiger = new IA() {
            @Override
            public void cry() {
                System.out.println("嗷嗷嗷嗷");
            }
        };
       tiger.cry();
    }
}
interface IA {
    public void cry();
}

本来我们的接口是不可以直接实例化对象的,但这里就相当于重写了cry()方法,并没有实例化它的对象。

class Outer {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.method();
    }
    private int m = 10;
    public void method() {
        //需求:使用一个IA接口,并创建一个对象
        //传统写法:写一个类,实现该接口
        //现在我们不要Tiger类
        //使用匿名内部类来简化代码
        //此时的编译类型是:IA接口
        //此时的运行类型是:匿名内部类
        /*
            底层:
            class XXXXXXX(类名) implements IA {
            @Override
            public void cry() {
                System.out.println("嗷嗷嗷嗷");
            }
        };
         */
       IA tiger = new IA() {
            @Override
            public void cry() {
                System.out.println("嗷嗷嗷嗷");
            }
        };
       tiger.cry();
    }
}
interface IA {
    public void cry();
}

 现在我们来看看它在底层中具体的名字:

System.out.println(tiger.getClass());我们用getClass()方法来获取名字。

 它的名字就是: class 包名.外部类名$1

匿名内部类的使用细节:

1.匿名内部类既是一个类的定义,又是一个对象;从语法上看它既有类的特性又有对象的特征。

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

3. 不可以添加修饰符,因为他就是个局部变量

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

5.外部类不可以访问匿名内部类(因为他是个局部变量)

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

实例内部类

在外部类中,内部类定义位置与外部类成员所处的位置相同,因此称为成员内部类
即未被static修饰的成员内部类

说明:

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

例:

public class Main {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.T();
    }
}
class Outer {
    private int n1 = 10;
    class Inner {
        public void say() {
            System.out.println("Outer 中的 n1 = " + n1);
        }
    }
    public void T(){
        Inner inner = new Inner();
        inner.say();
    }
}

 只能通过这种方式访问。

2. 实例内部类所处的位置与外部类成员位置相同,因此也受public、private等访问限定符的约束
3. 在实例内部类方法中访问同名的成员时,优先访问自己的,如果要访问外部类同名的成员,必须:【外部类名称.this.同名成员 来访问】
4. 实例内部类对象必须在先有外部类对象前提下才能创建
5. 实例内部类的非静态方法中包含了一个指向外部类对象的引用
6. 外部类中,不能直接访问实例内部类中的成员,如果要访问必须先要创建内部类的对象。

静态内部类

被static修饰的内部成员类称为静态内部类

public class Main {
    public static void main(String[] args) {
        // 静态内部类对象创建 & 成员访问
        OutClass.InnerClass innerClass = new OutClass.InnerClass();
        innerClass.methodInner();
    }
}

class OutClass {
    private int a;
    static int b;

    public void methodA() {
        a = 10;
        System.out.println(a);
    }

    public static void methodB() {
        System.out.println(b);
    } // 静态内部类:被static修饰的成员内部类

    static class InnerClass {
        public void methodInner() {
        // 在内部类中只能访问外部类的静态成员
        // a = 100; // 编译失败,因为a不是类成员变量
            b = 200;
        // methodA(); // 编译失败,因为methodB()不是类成员方法
            methodB();
        }
    }
}

【注意事项】
1. 在静态内部类中只能访问外部类中的静态成员
2. 创建静态内部类对象时,不需要先创建外部类对象
3.作用域:同其他成员,为整个类体

4.如果外部类和局部内部类成员发生重名时,默认遵守就近原则,如果向想访问外部类的成员,可以使用(外部类名.成员名

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/26139.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

净亏损2.9亿元,财务业绩陷入困境后,逸仙电商盈利仍遥遥无期

来源:猛兽财经 作者:猛兽财经 逸仙电商概况 逸仙电商(YSG)是一家开曼群岛控股公司,通过与可变利益实体(“VIE”)的合同协议,在中国生产和销售化妆品和美容产品。公司结构如图所示。 逸仙电商成立的目的是…

不懂Hybird开发,感觉错过一个亿~

从当前移动开发的实际情况来看,移动端的开发方式三分天下:纯原生(Native App)、混合开发(Hybird App)、网页应用(Web App)。 ​ 纯原生(Native App)&#xff…

附录10-JS正则

在JS中有多种内置方法可以使用正则表达式,比如说match,exec,test等 文章参考 第十四章 吃通js正则表达式,javascript前端工程师必会技能_哔哩哔哩_bilibili 目录 1 正则常用方法 1.1 exec的简单使用 1.1.1 基本使用 1.1.2 lastIndex属性 1.1.…

Android Activity跳转

实现点击按钮,发送消息并跳转到另一个Activity MainActivity添加SendMessage方法 const val EXTRA_MESSAGE "com.example.myfirstapp.MESSAGE"class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super…

【C++】string的使用

文章目录一、前言二、标准库中的string类三. string类的常用接口1. 构造函数2. 容量操作3. 访问遍历4. 修改操作5. 其他操作一、前言 C语言中,字符串是以\0结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数&#xff0…

ubuntu18.04服务搭建yolov5开发环境

文章目录1. 系统和显卡信息2. 下载安装CUDA2.1 1cuda环境变量配置1. 系统和显卡信息 (1) 系统信息 kanditelpo-System-Product-Name:~$ cat /proc/version Linux version 4.15.0-191-generic (builddlcy02-amd64-032) (gcc version 7.5.0 (Ubuntu 7.5.…

PDF如何转Word?分享几个实用办公软件给你

PDF是我们常用的文件格式,因为它的兼容性好,在手机、电脑查看文件都不影响文件的格式与内容。并且它的保密性也好,因为它无法在线更改文件内容,但这也说明了,我们如果需要对其进行更改的话,将需要把PDF格式…

解决Vue3中echarts无法缩放的问题

这里写自定义目录标题前言问题描述官网示例正常官网示例在本地缩放异常灵光乍现问题解决前言 实际工作中,使用到vue和echarts技术。项目原来用的vue2echarts4,后来更新到了vue3echarts5,结果遇到echarts无法绽放的问题。 问题描述 官网示例…

PDF、Word、Excel文件前端预览实操干货都在这!

随着Odoo在各个行业领域的深入应用,对Odoo的前端交互体验要求也越来越高。 我们在项目开发中常常会遇到,需要上传文件并预览的问题。 这里是我遇到的需求,并完成的一个小demo。 在Odoo中实现文件上传 首先我们需要在qweb页面中加入上传的…

Chrome浏览器插件开发v3版本第二篇:改变页面布局案例

跟着官方教程走才是硬道理:https://developer.chrome.com/docs/extensions/mv3/getstarted/tut-focus-mode/ 老规矩,搭建基本的项目结构:创建一个manifest.json文件 {"manifest_version":3,"name":"Focus",&…

[附源码]Python计算机毕业设计宠物销售管理系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

SQL Server中row_number函数用法介绍

一、SQL Server Row_number函数简介 ROW_NUMBER()是一个Window函数,它为结果集的分区中的每一行分配一个连续的整数。 行号以每个分区中第一行的行号开头。 语法实例: select *,row_number() over(partition by column1 order by column2)…

PaddlePaddle飞浆搭建和机器学习文字识别

PaddlePaddle飞浆搭建和机器学习文字识别 文章转自:https://lingkang.top/archives/paddlepaddle-fei-jiang-da-jian-he-ji-qi-xue-xi-wen-zi-shi-bie 官网:https://www.paddlepaddle.org.cn/ 飞桨(PaddlePaddle)以百度多年的深…

第七章:Springmvc中applicationContext.xml配置文件应用上下文详解

主要配置程序的总体用上下文,让容器对全局掌握来龙去脉 1.扫描所有项目的包名 2.配置项目所有的静态资源映射 3.配置请求方法的映射驱动 4.配置适配器适配RequestMapping注解标注的Handler(HandlerMethod类型) 5.配置消息转换器决定浏览器以什…

Unity游戏Mod/插件制作教程04 - 如何创建配置文件

ConfigEntry<T> 在插件功能的设计中&#xff0c;经常会有需要玩家自己配置的东西&#xff0c;比如插件的各种设置&#xff0c;快捷键的分配等。在BepInEx中&#xff0c;提供了一个ConfigEntry类简化了配置操作。 我们来看一段示例&#xff1a; (注:由于阿B在代码页中会…

Docker的网络模式

一、Docker网络 1.1 Docker网络实现原理 docker 使用linux 桥接&#xff0c;在宿主机虚拟一个docker 容器网桥&#xff08;docker0) &#xff0c;docker 启动一个容器时会根据docker 网桥的网段分配给容器一个IP地址&#xff0c;称为Container-IP&#xff0c;同时Docker 网桥…

JAVA接入OPC DA2.0引发的问题

背景&#xff1a; JAVA接入OPC DA后&#xff0c;在生产环境跑了一段时间后就会出现异常&#xff0c;给折腾的够呛&#xff0c;起初的报错还能通过重启OPC连接解决&#xff0c;后来强制重新连接也不行&#xff0c;最终一套测试下来&#xff0c;除非重启OPC服务器&#xff0c;别…

生产制造企业数字化转型:流程制造ERP

ERP的含义是企业资源计划&#xff0c;含义是对企业所拥有各种资源进行综合规划和优化管理&#xff0c;用以降低成本&#xff0c;提高效率&#xff0c;增加利润。ERP最初是在90年代初提出的&#xff0c;那时的ERP概念&#xff0c;还只是根据计算机技术的发展和供需链管理,推论各…

[附源码]java毕业设计校园闲置物品租赁系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

深度学习——动物数据集大合集(附下载地址)

说明&#xff1a;部分数据收费&#xff0c;付费后数据请关注私信内容&#xff0c;会给出下载链接&#xff0c;亲测数据质量不错&#xff0c;如下图所示&#xff1a; ​ 1、30种常见鱼类数据集 数据集介绍&#xff1a;30种常见鱼类数据集&#xff08;每类鱼30-100张图片不等&am…