Java类和对象(三),封装,static,代码块,OJ练习

前言❤️❤️

hello hello💕,这里是洋不写bug~😄,欢迎大家点赞👍👍,关注😍😍,收藏🌹🌹
请添加图片描述
🎇个人主页:洋不写bug的博客
🎇所属专栏:Java学习之旅,从入门到进阶
🎇铁汁们对于Java的各种常用核心语法(不太常用的也有😆),都可以在上面的Java专栏学习,专栏正在持续更新中🐵🐵,有问题可以写在评论区或者私信我哦~

前序

(链接挂在下面了)。这部分知识有一点点抽象,那特别是我加粗的字体,大家耐心读几遍,应该还是能理解的差不多的,加油,奥里给!!!

最基础篇
进阶篇

1,封装

1,基础概念

笔记本电脑和手机,我们经常使用它,但是却不知道它内部的电子元件是如何工作的
类似的东西还有很多,像冰箱,汽车,电视等等
这种只使用,而不知道内部细节的东西就是封装。

封装的核心就是把细节隐藏起来,在Java中,封装有三个意思:

  1. 创建方法时,把方法实现的细节藏起来;
  2. 创建类,把类实现的细节藏起来;
  3. 实现网络协议,把下层协议藏起来。

现在重点要学的就是创建类,把类的细节藏起来,这就指的是类中的方法属性,只能在类内部使用,在外面感知不到。

概念:
private修饰的属性,方法,就是只能在类的内部使用,这就是封装。
public修饰的属性,方法,可以在类外部使用,这就不是封装。

写代码的时候,不能直接全部用private修饰(封装),当然也不能全都用public修饰(不封装),哪些属性方法要public/private,其实是取决是具体的场景的

2,代码解释

光看概念可能有点抽象,在类和对象(一)的博客中,定义了一个学生类,用来演示类怎么定义,里面无脑的全部使用了public
这里把学生个人的隐私内容用private给封装起来,方法仍然去使用public
代码如下:

public class Student {
    private int id;

    private String name = "大明";

    private int age;

    private String gender;

    private double score;

    public void doHomework(){
        System.out.println(name + "同学在做作业");
    }

    public void study(){
        System.out.println("同学在学习");
    }
}




Java类和对象(三)的博客提到了用包来管理代码,这里在csdn这个包里再创建一个exercise类,用来进行测试
在这里插入图片描述

这个exercise就是相同包中的其他类,接下来在exercise类中创建一个学生对象,然后我们在分别看下是否能够调用方法和获取学生姓名。

public class exercise {
    public static void main(String[] args) {
        Student student = new Student();
        student.study();
        System.out.println(student.name);
    }
}

这里方法是可以正常调用,但是学生的姓名却没办法获取,这是因为把name属性设置成了private

在这里插入图片描述




private数据在类外无法获取,在Student类内部是可以获取使用的
代码示例如下:
在Student类中的doHomework方法这里同样使用了name,这里不会爆红,
在类外调用该方法,也会正常打印出学生的名字

在这里插入图片描述

public class exercise {
    public static void main(String[] args) {
        Student student = new Student();
        student.doHomework();
    }
}

在这里插入图片描述



有的铁汁到这就会说:你用private来保护这些学生的个人信息在外面的类中不会被直接读取到,同时又在方法中加入学生的姓名,在类外面打印方法就又能知道学生姓名。那这样折腾图什么呢

其实是这样的,封装并不是表明把这些变量彻底封死,如果都彻底封死,那干脆就不用定义这些变量了
封装只是限制一下在类外读取这些数据的方式。
大家不要小看这个小小的限制,这里封装后只能通过一些方法来读取;如果不封装的话,那么这些变量在外面不仅能被调用,也能被胡乱修改
封装后,如下图所示,在类外面,如果尝试读取变量的话,根本读取不了,甚至类的使用者都不知道这个类中有什么变量

在这里插入图片描述

3,get和set方法

封装远远不只是用public和private这么简单,还可以用set,get方法来实现对类的封装。

例如在Student类中,想要放出gender(性别)的修改权限,但是又害怕调用者乱改,凡是gender,都是male/female
但是就是怕有的人乱改,这点在国外比较明显,比如把性别设定成沃尔玛购物袋,武装直升机什么的
那怎么限定调用者乱改呢,就需要写一个自定义的set方法,只需要让调用者输入自己到底是不是男的就行了,是男的输入true,是女的输入false,这样性别就非常正常了。

如果想让用户只读取数据,不修改数据,那就需要用到get方法,用户想查看这些信息时就使用get方法,只有一个读取的作用

public class Student {
    private int id;

    private String name = "大明";

    private int age;

    private String gender;

    private double score;

    public void doHomework(){
        System.out.println( name + "同学在做作业");
    }
    public void setGender(boolean isMale){
        if(isMale){
            gender = "male";
        }else{
            gender = "female";
        }
    }
    
    public  String getGender(){
        return gender;
    }

    public void study(){
        System.out.println("同学在学习");
    }
}
public class exercise {
    public static void main(String[] args) {
        Student student = new Student();
        student.setGender(true);
        System.out.println(student.getGender());
    }
}

在这里插入图片描述

4,get和set方法的自动生成

在类中按alt + insert键,就可以自动生成这些方法,Getter and Setter选项的意思就是同时生成get和set方法

在这里插入图片描述


选中age,点击ok,就可以生成age的get和set方法
在自动生成后也可以根据自己的需要对进行修改
铁汁们熟练get和set方法后,就不再写了,都是自动生成的

在这里插入图片描述

在这里插入图片描述



自动生成时,可以按住ctrl键,用鼠标点击选中多个成员变量,同时生成多个成员变量的get和set方法,这样就非常高效

在这里插入图片描述

2,static关键字

1,发展演化过程(有兴趣看)

这个static关键字其实在最早C语言的时候就已经有了,那时候主要有以下三个用途:

①:修饰局部变量,把变量的生命周期延长,跟随整个程序

在这个func函数中,如果正常不写static的话,每次调用完方法都会销毁count变量,下次调用时count的值就是0
写了static,方法执行完count值不会销毁,只有整个程序都运行结束count才会销毁
那执行过一次func方法,下次再执行,count的初始值就是1了,不是0

void func() {
    static int count = 0;
    count++;
    printf("count: %d\n", count);
}

下面这句代码是只运行一次的,因为每次出方法count都不会被销毁,也就不需要再初始化count

  static int count = 0;

②:修饰全局变量,把变量的作用域限制到到当前的.c文件中,不能在其他的源文件中使用,因此,在其他的源文件中也可以定义名字相同的变量。

③:修饰函数,也是把函数的作用域限制到了当前的.c文件中去,跟限制全局变量的效果类似。




最初在C语言中static就是这几个意思,看完后就会发现这跟Java中的static用法不沾边,那在演化过程中为什么有如此巨大的差异呢?那就要从头说起了

在美国有一个超级牛逼的实验室,叫贝尔实验室,像太阳能电池,通信卫星,电子数字计算机,都是贝尔实验室发明的,而贝尔就是最早发明电话的那个人,这个实验室有一多半的人都获得过诺贝尔奖,C语言跟C++的发明人就都是这个实验室的。

在这里插入图片描述

后来,在创建C++时,需要一个词来表示这样的概念,那就是类属性/类方法(稍后博客会重点去说),这时候重新引入一个新的关键字风险是有点高的
因为写C语言跟C++的软件,其实是通用的,引入一个新的关键字可能会破坏兼容性
因此,创建C++的大佬就想着把C语言中的static搞过来,用一下,就算原来的定义跟现在没啥关系

Java是在C++之后创建的,C++创建类的对象的基本思路跟Java是相似的,因此创建Java的大佬就把这个C++中这个static概念搞了过来,直接就用了。

2,类属性/类方法

类属性和普通属性:

如下图,在Student中定义的这些变量没有加staic,都是普通属性
普通属性在创建对象的时候会被初始化,调用是通过创建的对象后面加上点来调用,也就是通过对象来调用的。

在这里插入图片描述




类属性就是在定义变量前加入了static,类属性跟普通属性在初始化和调用上都是有所不同的

  • 类属性是属于类(加static),普通的属性(不加static)就属于对象,类属性其实比普通属性更牛的,高一个级别,类属性在类加载时就能初始化,而普通属性只有在创建对象时才会被初始化。
  • 类属性因为是属于类才,所以在调用时就是通过类名来调用(用对象调用也可以,但还是建议通过类名调用),而实例属性只能通过对象来调用



  • 我们可以在Student类中写一个main方法测试一下,我们会发现,加上static的属性都可以用类名来调用。

    在这里插入图片描述

    在这里插入图片描述




    再创建一个对象,试试能不能调用刚刚加static的那三个变量,这里是不行的
    在这里插入图片描述





    类方法和普通方法的解析:

    类方法和普通方法主要就是调用的区别,因为方法是不用初始化的,因此就不存在初始化的区别,类方法是通过类来调用,对象调用不了;普通方法就是对象调用的。



    在Student类中写一个study方法,前面加上static

    在这里插入图片描述

    在Student类中的main方法中试一下,无需创建对象,就可以用类名来调用(如下图)
    可以再创建一个对象试一下,看对象能不能强制调用static方法
    再把static删了,再看看类能不能调用,跟前面的类属性/实例属性效果相似

    在这里插入图片描述

    3,深度解析(代码)

    1,调用补充

    下面是用对象强制调用类属性,这里并不建议这样做,还是建议用类去调用,真是强制用对象调用也不会报错,示例如下:

    package csdn;
    
    public class Student {
        private static int id;
    
        private static String name;
    
        private static int age;
    
        private String gender;
    
        private double score;
    
        public void doHomework(){
            System.out.println( name + "同学在做作业");
        }
        public void setGender(boolean isMale){
            if(isMale){
                gender = "male";
            }else{
                gender = "female";
            }
        }
    
        public  String getGender(){
            return gender;
        }
    
    
    
        public static void  study(){
            System.out.println("同学在学习");
        }
    
        public static void main(String[] args) {
           Student student = new Student();
            System.out.println();
    
        }
    }
    
    

    选项框里并没有类属性

    在这里插入图片描述

    自己打出来,也不会报错,只是会有个警告。

    在这里插入图片描述

    2,类属性属于整个类(内存)

    类属性是属于整个类的,比如我们在一个类中创建三个对象,那么像gender,score这些普通属性就会有三份,但是id,String,age都是只有一份,因为它们是类属性,是被所有对象所共有的

    在这里插入图片描述





    使用代码来验证一下,这里为了方便验证,就用对象来调用这个类属性,日常写代码不建议这样做

    public class Test {
        public int n = 10;
    
        public static int m = 20;
    
        public static void main(String[] args) {
            Test t1 = new Test();
            t1.n = 100;
            t1.m = 200;
    
            Test t2 = new Test();
            t2.n = 300;
            t2.m = 600;
    
            System.out.println("t1.n = " + t1.n);
            System.out.println("t1.m = " + t1.m);
            System.out.println("t2.n = " + t2.n);
            System.out.println("t2.m = " + t2.m);
        }
    }
    

    通过打印结果就可以看出,这个类属性在类中是只有一份的,因此,是以最后修改的为准

    在这里插入图片描述

    n为成员属性(变量),只要是new出来的东西,都是储存在堆上的,new出来的Test对象t1,t2就是储存在堆中,n随着对象储存在堆中;因此,创建几个对象,n就有几份。

    m是类属性,它总共只有一份,就储存在方法区中()。

    在数组基础博客的第5部分,是Java相关的内存知识,对内存还不太清楚的铁汁们可以看一下,下面这张图片在那篇博客上截取的,方法区就是内存区域的一部分

    数组基础
    在这里插入图片描述

    方法区不同于堆和栈空间,它是存储整体类的信息,下面图中整个大长方形就是方法区,里面的小格子是他存储的信息

    在这里插入图片描述




    静态成员变量(类属性,不加static直接说是成员变量)的特征:
    1,不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中。
    2,既可以通过对象访问,也可以通过类名访问,但是建议通过对象访问。
    3,静态成员变量存储在方法区中
    4,生命周期伴随类的一生(从程序启动开始,到程序结束为止)

    3,类方法

    static修饰的方法就是类方法,类方法跟类有关,跟对象(实例)无关
    static修饰属性,决定对象存储的位置,而static修饰方法,是不影响方法存储的位置,因为方法都是储存在方法区中的。

  • 不加static就是实例方法,就得通过实例名.方法名来调用,此时方法内部也可以使用实例属性(也就是成员变量,不加static定义的)和其他的实例方法(不加static定义的方法)
  • 加了static就是类方法,就得通过类名.方法名来调用,对象.方法名也可以,但是不推荐,示例如下:

  • public class Test {
        public int n = 10;
    
        public static int m = 20;
    
        //普通的实例方法
        //可以使用实例属性,也可以使用类属性
        public void func1(){
            System.out.println(n);
            System.out.println(m);
        }
    
        //类方法
        //只能使用类属性,不能使用实例属性
        public static void func2(){
            System.out.println(n);
            System.out.println(m);
        }
        public static void main(String[] args) {
    
        }
    }
    

    在类方法中只能使用类属性,不能使用实例属性,这里在类方法中调用实例属性(成员变量),就会爆红,显示调用不了。

    在这里插入图片描述

    总结就是:实例方法中可以使用实例属性,也可以使用类属性。而类方法中只能使用类属性,不能使用实例属性




    接下来再看下方法的调用规则

    public class Test {
        public int n = 10;
    
        public static int m = 20;
    
        //普通的实例方法
        //可以使用实例属性,也可以使用类属性
        public void func1(){
            System.out.println(n);
            System.out.println(m);
            
        }
        
        public void func2(){
            func1();
            func3();
            func4();
        }
    
        public static void func3(){
            func4();
            func1();
        }
        
        public static void func4(){
            
        }
        public static void main(String[] args) {
    
        }
    }
    

    这里func2(实例方法)对于类方法和实例方法都可以调用,但是func3(类方法)就只能调用类方法了,尝试去调用实例方法就会报错。

    在这里插入图片描述

    在对实例方法的调用这里,其实本质上是有个this的,只是写的时候省略了,this指的是通过当前调用方法的对象来调用该方法

    在这里插入图片描述

    这个到底哪个可以调用哪个,有个记忆技巧
    只需要记住static修饰的方法里面,是没有默认this的,this就是用来调用实例方法的
    也就是在static修饰的方法(类方法)里面不能使用实例方法和实例属性




    我们看下这段代码,在类方法中调用n这个实例属性就会报错

    public class Test {
        public int n = 10;
    
        public static int m = 20;
        
        public static void main(String[] args) {
            System.out.println(n);
            System.out.println(m);
        }
    }
    
    

    报错的英文翻译过来就是无法从静态(加了static)上下文中引用非静态(不加static)字段

    在这里插入图片描述

  • 补充:这里的main方法也是一个类方法,调用时也是通过类名.main来调用的,只不过这个调用过程不用我们手写,是JVM自动完成的
  • 3,代码块

    一个代码块就是一个{ }
    一个类也是可以通过{ }进行初始化的。

    1,普通代码块

    定义方法{ }
    if{ }
    while{ }
    for{ }
    这些都是普通代码块。

    2,构造代码块/静态代码块

    构造代码块也叫做实例代码块,就是定义在类中的代码块,不加修饰符,构造代码块一般用于初始化成员变量。
    里面写的内容是对成员的初始化操作,执行时机就是在new对象的时候
    构造代码块是不用static修饰的,里面是有this的,可以访问类属性/类方法,也可以访问实例属性/实例方法。

    使用static定义的代码块称为静态代码块,一般用于初始化静态成员变量。
    执行的时机就是在类加载的时候,一般只执行一次,在 Java 中,静态代码块一般是类中最早执行的代码
    类就好比是一个房子的图纸,而对象就是根据这个图纸去建造房子,静态代码块相当于在图纸的研发阶段就执行了。

    下面这段代码的main方法是空的,但是只要加载了这个类,就会运行这个构造代码块

    public class Test {
        public int n = 10;
    
        public static int m = 20;
    
        //构造代码块
        {
            n = 20;
            m = 10;
            System.out.println("执行构造代码块");
        }
    
        static{
            m = 30;
            System.out.println("执行静态代码块");
        }
        public static void main(String[] args) {
    
        }
    }
    

    在这里插入图片描述

    在main函数里面创建两个对象,看运行结果就知道,静态代码块只随着类的加载执行一次,而构造代码块每创建一次对象,都会执行一次:

        public static void main(String[] args) {
            Test t1 = new Test();
            Test t2 = new Test();
    
        }
    

    在这里插入图片描述



    注:静态代码块是大括号前面只有一个static的
    像main方法,还有那些用static修饰的静态方法,都不是静态代码块
    方法不属于任何代码块,代码块大括号前面只有什么都不写或者只能有一个关键字(比如if while static)




    这只是有这样一个概念,在平常写代码时,基本上不用静态代码块
    静态代码块主要就是初始化静态属性,在定义这个静态属性的时候一般可以直接初始化,也就是就地初始化,再去写个代码块去初始化就有点太麻烦了😅

    在这里插入图片描述

    4,OJ题

    注:这种OJ题面试时是检查切窗口的,在面试时我们如果切到IDEA环境下来写,就会被检测出作弊。

    1,修改Data类的定义

    题目链接

    在这里插入图片描述
    在这里插入图片描述

    这里的构造方法和get方法都是私有的,在main方法中无法访问,我们要把它改为public;另外,在构造方法中,实参的名字跟成员变量名字相同,编译器无法区分,要加上this

    在这里插入图片描述

    2,验证年龄

    题目链接
    在这里插入图片描述

    这也是一个非常基础的题目,就是让我们补全一下类,再加上一个判断逻辑:

    在这里插入图片描述

    5,概念题(知识补充)

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

    这段代码的运行结果是什么???
    A.代码编程成功,并输出”s=”
    B.代码编译成功,并输出”s=null”
    C.由于String s没有初始化,代码不能编译通过。
    D.代码编译成功,但捕获到NullPointException异常

    这里选C,因为这里的s是局部变量,局部变量必须初始化,才能打印,否则编译都通过不了




    阅读如下代码。 请问,对语句行 test.hello(). 描述正确的有()

    
    package NowCoder;
    class Test {
    	public static void hello() {
    	    System.out.println("hello");
    	}
    }
    public class MyApplication {
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		Test test=null;
    		test.hello();
    	}
    }
    

    A.能编译通过,并正确运行
    B.因为使用了未初始化的变量,所以不能编译通过
    C.以错误的方式访问了静态方法
    D.能编译通过,但因变量为null,不能正常运行

    这道题大家应该一看A这个选项,就直接排除了,但是这道题就是选A。

    那创建个空的对象也能调用方法吗

    我们前面在说static的时候提到,static方法其实是属于类的,因此建议用类去调用
    如果强制用对象去调用也不会报错(这个方法实际上跟对象是没关系的),这里编译器在运行的时候,会把test.hello();这句转为Test.hello();不看对象,因此对象为null也能正常运行




    这段代码的运行结果是什么

    public class Pvf{
        static boolean Paddy;
        public static void main(String args[]){
            System.out.println(Paddy);
        }
    }
    

    答案是编译通过并输出false,
    成员变量在创建时会有默认的初始值,数字类型默认值是0,boolean是false,像String这些引用类型默认是null

    结语💕💕

    这些部分就是属于类和对象中相对比较进阶的,铁汁们多练代码,一定可以掌握的👍👍👍

    以上就是今天所有的内容啦~ 大家都学废了吗?完结撒花~ 🥳🎉🎉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值