1、类的特性-封装
class是JAVA提供给我们自定义的数据类型的关键字。
就是为了满足可以描述这世间的事物。这个数据类型有很多的特性。封装就是其一。
所谓封装,就是将内部实现的细节隐藏起来,只对外暴露简单的方法,外界直接调用方法,而不必关系内部的实现逻辑。
追求的高内聚、低耦合。
-
高内聚:类的内部数据操作细节自己完成,不允许外部干涉
-
低耦合:仅对外暴露少量的方法
其实,生活中很多这样的例子。如 用遥控器开空调,只需要按一下开关键即可。不需要知道空调内部到底是怎么执行的。
1.1 权限
要实现该暴露的暴露,该隐藏的隐藏,就需要引入权限了。
JAVA提供了4中权限,按从大到小排列是:public、protected、缺省、private
-
private:私有的。以类为单位,类的私有,就是只能在本类内部访问。
-
缺省:就是不写修饰符。权限扩大了一下。在这个类所在的文件夹下,其他的类也可以访问。可以认为同一个文件夹下其他类都是兄弟类,同一个文件夹就是同一个父亲。当然,java中文件夹都叫做包。也就是同一个包内的所有内都能访问。
-
protected:受保护的。权限又扩大了一点。加上这个类有儿子类怎么办。这个儿子类又不在我们这个包下,毕竟是儿子嘛,也给予它的访问权限。即 同一包下所有类可以访问,还包括不同包下的子类可以访问。
-
public 公共的:没的说,这个就是 不管在那,不管是不是子类,都给你访问权限。
以上可以看出:权限的主角是 类本身。能不能访问看和类的关系,有控制兄弟(default)能不能访问的,也有控制儿子(protected)不能把访问的,还有控制路人(public)能不能访问的。
这是针对类的成员【包括成员变量、成员方法、内部类、构造器,不包括代码块】来说的。
对于类,还不一样。类只有2中权限:public、default。
public:都可以访问
default:本包下可以访问。
1.2 属性的封装
如果属性设置为public,那么大家在本项目任意处都可以访问。可以访问就意味着可以修改、获取。
但是一个自定义的类,是用来描述特点的事物的,比如动物类,他的性别属性。只能是 公或者母。
如果是公共权限,那么就无法控制 别人对性别属性的修改。
所以,为了达到我们相要的目的,即 不能随便设置值。我们就不把这么大的权限给外界了。只提供一个可以设置的方法,在这个方法里面添加限制。满足条件再设置属性值。这样就达到了精细控制属性的目的了。
所以:有要求的属性一般设置为私有的,只能是本类可以访问。并提供公共的方法,给外界调用。这就是为私有属性的get和set方法。
封装性的体现需要权限的配合。
2、构造器
为什么会有构造器?
我们知道,我们自定义的类都是new 出来的。而new 这个关键字是怎么根据模板创建出对象的?
答案就是构造器。如果我们不写构造器,java会默认提供一个无参构造器。每次new都会调用这个无参构造器,去创建对象。
构造器的特点:
-
和类名相同
-
没有返回值类型。与void不同,void也是一种返回值类型。没有就是不写的意思。
-
不能被static、final、synchronized、abstract、native 修饰,不能有return
-
可以被权限修饰符修饰
再看一下 new 对象的过程:
Animal animal = new Animal();
等号的右边其实就是在调用 Animal() 构造器。
只不过不是通过对象点的方式调用,而是new + 构造器。
真的没有返回值吗? 你看 new Animal() 赋值给了 Animal 类型的 animal变量。
这说明是有的。
实际上,构造方法是由jvm调用的,返回值就是类的类型,这是固定的,JVM会自己加上。
构造器就是一种特殊的方法,也是支持方法重载的。
public class Animal {
// 年龄
public int age;
// 性别
public String sex;
// 体重
public static final int weight = 10;
// 无参构造器
public Animal() {
}
// 有参构造器
public Animal(int age, String sex, int weight){
int min = 0;
int max = 120;
if (age > min && age <=max){
this.age = age;
}else {
this.age =min;
}
this.sex = sex;
}
}
上面的代码 写了2个构造器,一个有参,一个无参。
为什么需要有参构造器呢?
你应该发现了,当我们在定义数组时,可以这样定义
String[] a = new String[]{"hello", "world"};
这就是数组的静态初始化。
没错,有参构造器的存在也是为了对象初始化用的。
可以如上图这样,使用有参构造器,在创建对象时,直接初始化。
注意:
-
我们不写构造器时,JAVA会默认提供一个无参构造器。
-
当我们写了一个有参构造器时,JAVA就不会再提供无参构造器了,如果还需要无参构造,需要自己加上。
-
构造器只能写2个吗?不是的,满足方法的重载条件,写多少个都可以。当然同时要满足构造器的条件,不能有返回值,不能被一些修饰符修饰等。
2.1 属性赋值的顺序
讲到构造器,就可以总结一下,一共有多少种属性赋值的方式,以及顺序。
1、默认初始化
2、显式初始化
3、构造器中赋值
4、对象.方法(属性私有) 或者 对象.属性(属性不是私有,且可以访问)
//默认初始化
public int age;
// 显式初始化
private int age = 20;
// 构造器中赋值
Animal animal = new Animal(20);
public Animal(int age) {
this.age = age;
}
// 对象.方法(属性私有) 或者 对象.属性(属性不是私有,且可以访问)
Animal animal = new Animal();
animal.setAge(20);
从快到慢的顺序是: 1、2、3、4;
3、拓展知识
3.1、JavaBean
javaBean 就是一个java类。需要满足一定的条件
-
类是公共的 (public class)
-
必须要有无参的公共构造器
-
有私有属性,以及属性对应的公有get、set方法
javaBean的应用非常广泛,主要用于数据交互。
后面数据对象分型
-
VO,值对象(Value Object)
-
PO,持久对象(Persisent Object) 也可以叫 Entity
-
TO,(Transfer Object),数据传输对象
-
BO,(business object) 业务对象
-
POJO,(plain ordinary java object) 简单无规则对象
这些都是JavaBean。后续进行详解。
3.2 UML 类图
4、this 关键字
this 是啥?
this 就是指当前对象。
看下面的代码:
public class Animal {
// 年龄
public int age;
// 性别
public String sex;
// 体重
public static final int weight = 10;
// 有参构造
public Animal(int age, String sex, int weight){
int min = 0;
int max = 120;
if (age > min && age <=max){
this.age = age;
}else {
this.age =min;
}
this.sex = sex;
}
// 无参构造
public Animal() {
}
}
在有参构造中,就使用了this关键字。
this.age = age;
this.age = min;
this.sex = sex;
赋值右边的age、min、sex 和赋值运算符左边的 age、sex是不一样的。但是它们的名字是一样的。我们知道,同一个作用域中,是不允许出现2个相同的变量名的。
右边的age、sex实际上是Animal类的有参构造器的形式参数,是外界调用时传进行对对象进行初始化的。
如上图这样调用,在创建类对象时,使用有参构造器进行初始化。将传递过来的值,赋值给创建的对象。
那么this的作用也就出来的
-
this 可以区分左边的age和右边的age是不同的,左边的是类的属性。而右边的是局部变量。
-
当我们创建ani这个Animal类型的对象(变量)时,初始化的是ani,而不是其他的变量。所以这个this 指的是ani对象
如果是下面的调用呢?:
Animal ani = new Animal(18,"公", 100);
Animal ani2 = new Animal(20,"母", 30);
创建了2个对象,而类里面只有一个this变量,java是怎么知道 18要给ani对象,20要给ani2对象呢?
关键就是这个this。这个this可以知道,到底是给哪一个对象进行初始化赋值。
所以this真正指的是 当前对象。即
Animal ani = new Animal(18,"公", 100);
执行这段代码,this 就是 ani 对象
Animal ani2 = new Animal(20,"母", 30);
执行这段代码,this 就是 ani2 对象
-
this 指代的是 当前的对象。
指代当前对象,就说明 this 是一个对象。对象就能干对象能干的事。如调用属性,方法,构造器等。
this 是在 class 声明自定义数据类型时才有的。只能在这个类里面用。不同的类的this是不同的。
那么我怎么知道,当前对象是谁呢?
调用的时候就知道了。
就像 老板权辞退你。 不管谁是老板,都有这个权利,当你去了一家公司,自然,这个老板就是指你当前公司的这个老板。当你换了一家公司,这个老板就是指你现在待的这家公司的老板。
注意:
-
this 在调用构造器时,是创建对象。为了不陷入死循环,自己调用自己、你掉我,我调你,死循环调用。有些规定需要遵守。
-
构造器不能通过 this(形参列表) 来调用自己。 ---->要是能调用,就是自己调用自己,死循环。。
-
如果一个类中有n个构造器,最多有n-1个构造器使用 this(参数列表)。---->要是每一个里面都有,一定会陷入 互相调用的死循环。
-
this(形参列表) 必须声明在当前构造器的首行。 ---->就是说 如果要用,只能使用1次。
-
构造器内部 最多使用1个 this(形参列表)。 ---->也是要么不用,用的话最多1次。
5、package 关键字
package 就是包
包实际就是一个文件夹。一个文件夹就是一个包。
package com.xgzit.leetcode.utils;
package 是java类的第一行代码,声明这个类所属于的包。
使用点来区分包(文件夹)。关系为父子关系。
上述含义:这个类在utils 包里面,utils包在leetcode包里,leetcode包在xgzit包里,xgzit包在com包里面
引入package是为了更好的管理这些java文件。
一般一个类就是一个java文件,所以也可以说 管理这些类文件。
还记得权限吗?
-
private 是本类下。同包下的其他类也不能访问。
-
缺省 权限就是 同一包下可以访问
-
protected 就是 不同包的 子类可以方法, 勉强跨包,要求是子类才能跨包访问。
-
public是 同一项目下,跨包了!
JDK 提供的一些包的简介:
6、import 关键字
import 就是 导入的意思
使用import 导入其他包下的类或者接口。
import com.xgzit.leetcode.test.Animal;
位置:
在 package 与类之间
作用:使用不是本类的代码。就需要导入。
如果导入某个包的类比较多,可以使用*代替,表示所有
import com.xgzit.leetcode.test.*;
全类名:全类名是某个文件在项目中的位置,格式为 包名.类名