关于JAVA你必须知道的那些事(二):封装

时隔近一年,我突然想起来这个文章还没有发完,所以就继续开始写。也不知道自己上次写到哪里了,不管了这里从面向对象的三个特性说起。

类和对象

在这之前,我们先了解什么是对象,已经什么是面向对象?对象:万物皆对象,现实中实际存在的事物都可以看成一个对象。而面向对象就是人在关注对象, 关注事物的信息。那什么是类?类就是模子,通常用于确定对象将会拥有的特征(属性)和行为(方法)。也就是说对象是类的具体存在,而类则是对象的抽象化。苹果是一个类,你手里拿的苹果就是一个实例化的对象。

刚才说了对象具有属性和方法,那么属性和方法又是什么呢?属性就是对象具有的各种静态特征,通常用来说明对象有什么;而方法就是说明对象具有的各种动态行为,也即对象能做什么。

假如我有一辆吉普车,它的颜色,价格,型号就是属性;而它能加速,减速,停止就是具有各种方法。

创建类的一般步骤为:创建类==》实例化对象==》书写具体的逻辑。

通常我们在书写类的时候,都需要遵循单一职责原则(单一功能原则),也就是说 一个类应该有且只有一个引起功能变化的原因。如果在一个类当中承担的功能越多,那么它的交融,耦合性就越高,被复用的可能性就越低。特别是因为耦合度高,可能会因为一个职责的变化,引起其他职责的变化,进而影响整个程序的运行,这一点是我们所不想看到的。

实例化对象的过程可以分为三步:声明对象,实例化对象,将两者进行绑定。其中声明对象是在栈内存中开辟了一块内存空间,但此时还不是一个有效的对象,因为此时对象的空间里是空的。如果此时调用它的属性和方法则会引发错误。而实例化对象则是在堆空间开辟一块空间,它完成了具体对象相关信息的初始化操作。最后通过赋值进行两者绑定。

也就是声明对象和实例化对象是在内存中的不同空间完成的,通过赋值操作,将两者关联。具体的关联就是将堆中具体对象的内存地址存放在之前在栈中开辟的内存中,从而完成绑定。

构造方法

构造方法也称为: 构造函数或者构造器,你可以使用构造方法来完成对象初始化相关操作。

构造方法的调用必须配合new关键字,不能被对象单独调用。注意,构造方法必须与类同名且没有返回值。

方法名中的参数列表可有可无,但是只能在对象实例化的时候被调用。

当没有指定构造方法时,系统会自动添加无参的构造方法;当有指定的构造方法时,无论是有参、无参的构造方法,系统都不会自动添加无参的构造方法,一个类中可以有多个构造方法。

this: 当前对象的默认引用; this的使用:调用成员属性,解决成员属性和局部变量同名冲突,也可以调用成员方法。

如果你想调用重载的构造方法,那么只能通过this关键字来使用this();同时请记住,如果是通过this()来调用构造方法时,它必须放在方法体内第一行。(这个一定注意)

封装

封装就是将类的某些信息隐藏在类内部, 不允许外部程序直接访问,但是通过该类提供的方法来实现对隐藏信息的操作和访问。也就是说两点:一是隐藏对象的信息,第二留出可以访问的接口(方法)。

封装的具体步骤:1、将访问修饰符替换为private;2、提供公共的setter和getter方法;3、必须有构造方法(系统会默认调用无参的构造方法)。其中setter方法是可写,getter方法是可读。我们可以在setter方法里面添加自己的业务逻辑,从而实现对值的合理性进行判断。

因为已经实现了封装,因此我们在实例化对象的时候就不需要再次传入自定义的参数了,否则就没有使我们提供的setter方法生效了。

包的管理

为什么要说包的管理呢?因为包的管理太重要了,其实很多坑就是包的命令和管理不规范引起的。

我们知道文件夹可以进行文件的管理,同一个文件中可以存放多个不同的文件,同名的文件只能存放在不同的文件夹中。

在Java中我们也是通过包来管理java文件来解决同名文件的冲突问题,Java中一个包里不能存放同名类,但不同包却是可以。

包的定义必须放在Java源文件的第一行。前面说过,我们在定义类的时候,尽量遵循单一职责原则,同样的道理,在建立包的时候,建议每个包内存储的信息功能应该单一。

如何实现跨包类的调用?可以采用Import这个关键字,来实现包的导入。需要注意的是import包名. 只能访问指定包名下的类,无法访问子包下的类*。

还有就是包的效率问题,建议采用import包名.类名的方式进行包的导入,这样可以提高加载效率

import net.oschina.Test.*; // 加载包下的所有类import net.oschina.Test.Java; // 加载指定包下的指定类

注意一下,加载类的顺序跟import导入语句的位置无关:指定的具体包的优先级大于通配符。也就是下面加载会大于上面加载的速率。

最后说一下关于包管理的几个注意事项: 1、必须放在Java源文件中的第一行; 2、一个Java源文件中只能有一个package语句; 3、包名全部采用英文字母小写的方式; 4、包的命名方式为:域名倒序+模块+功能。

static关键字

static修饰

static表示静态的。

如果它修饰成员变量,那么该变量被称为静态成员或类成员,它是这个类所有的。也就是说无论这个类实例化出多少对象,它都会共用同一块内存空间。后面的只会覆盖前面的值。

如果它修饰属性,那么该属性被称为静态属性。

如果它修饰方法,那么该方法被称为静态方法。

如果它修饰初始化块,那么该初始化块被称为静态初始化块。

但是static是不能修饰类,不能修饰局部变量,不能内部类中修饰初始化块(不可以在内部类定义静态初始化块)。

静态成员的生命周期很长,在类加载时产生,直到类被销毁时才释放。

static访问

普通的成员方法可以直接访问当前对象(该类实例化的对象)的成员属性和方法,也可以直接访问当前对象的静态属性和静态方法

静态方法或者类方法(前面被static修饰),它不能直接访问同一个类中的非静态成员,因为它缺少隐含的this参数。静态方法只能直接调用同一个类中的静态成员。如果非要访问,只能通过实例化一个对象后,采用对象.成员方法的方式来访问非静态成员。

初始化块(代码块)

初始化块的说明

在Java里面,被{}括起来的代码就称之为代码块(初始化块)。

当代码块出现在方法里的时候,叫做普通代码块,普通代码块和一般语句的执行顺序是一样的:从上到下,顺序执行,先出现,,先执行。

当代码块直接在类中定义,与成员方法,属性并列时,我们此时称之为构造代码块。

记住构造代码块比构造函数优先执行。构造代码块它是在创建对象的时候被调用,优先于构造方法的执行。所以不管构造代码块放在类的其他位置,它都会先于构造函数执行。

多个构造代码块之间有先后顺序,但都先于构造函数前执行。

初始化块的执行

现在考虑一下,静态初始化块,普通初始化块,构造函数这三者的执行顺序?你只要记住静态初始化块静态初始化块只在类初始化时进行加载,而且只执行一次。对于三者,程序的执行优先级:静态初始化块--》初始化块--》构造方法。(这里的初始化块包括构造初始化块(直接在类中声明)和普通的初始化块(在方法中声明)。

初始化块的范围

看一段代码:

public void test(){
        {
            System.out.println("我是普通代码块1");
        }
        System.out.println("初始化块的范围");
        {
            System.out.println("我是普通代码块2");
        }
    }

我们发现这个test方法空间被分成了三部分,所以我们可以利用这个功能来实现变量的命名冲突。

public void test(){     int temp =10;     int temp =12;}

上面是不可以的,但是下面却是可以的:

public void test(){
{     int temp =10;
 };
       
 {    int temp =12;
};
    }

这时两个代码块空间中允许有自己的变量值,不会重名造成冲突。但是不能在方法的全局域位置添加同名变量,因为它会与两个变量都造成重复定义的问题:

public void test(){
{     int temp =10;
 };       int temp =11;
 {    int temp =12;
};
    }

因为temp的作用域是从那里到结尾的,会与后面的代码块里面的变量产生命名冲突。

由于篇幅的问题,继承和多态我下次再说哈,今天就写到这里了,感谢你的赏阅!!!

THANK YOU

Design by Envy

原文发布于微信公众号 - 啃饼思录(kbthinking)

原文发表时间:2018-11-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏算法channel

Python|编写自己的类

01 类(对象) class dog(object) 以上定义了一个dog对象,它继承于根类object. 02 类的属性 def __init__(s...

3695
来自专栏LEo的网络日志

python技巧分享(十一)

2548
来自专栏黑泽君的专栏

Java中,局部内部类

局部内部类 A:局部内部类可以直接访问外部类的成员。 B:局部内部类在局部位置可以创建内部类对象,通过内部类对象调用内部类方法,来使用局部内部类功能。 ...

2833
来自专栏大愚Talk

我对变量产生了这些想法

最近在学习Golang的过程中,发现一个有意思的事情,有的文章说函数调用传参时 slice 是引用传递,有的说是值传递。为什么同一个东西大家会不同认识?为了搞清...

841
来自专栏菜鸟计划

javascript 变量、作用域和内存问题

一、基本类型和引用类型的值   1.基本类型和引用类型的值  基本类型值:指那些保存在栈内存中的简单数据,即这种值完全保存在内存中的一个位置,他们所占据的空间大...

3728
来自专栏LEo的网络日志

python技巧分享(十一)

1404
来自专栏Pythonista

__slots__(面向对象进阶)

1024
来自专栏前端小栈

转 javascript基础详解-执行环境与作用域链

函数调用都有与之相关的作用域和上下文。从根本上说,范围是基于函数(function-based)而上下文是基于对象(object-based)。换句话说,作用域...

561
来自专栏web前端教室

var a="xx";a=a+"ss";a的值变了,但"xx"字符串并没有变

如题目所示, var a="xx"; a=a+"ss"; console.log(a); //xxss 一般情况下,我们就可以认为此时a的值,由'xx'变成了'...

2008
来自专栏iOS开发攻城狮的集散地

run timeimport : 成员变量、类、方法

1839

扫码关注云+社区

领取腾讯云代金券