前言
学习了封装的概念、权限修饰符、标准的Java类的定义、static【静态与非静态】、成员变量和局部变量、‘’==与EQUALS方法的比较、hashcode、类加载原理以及分析
提示:以下是本篇文章正文内容,下面案例可供参考
一、封装的概念
1.什么是封装
封装是面向对象的三大特征之一,它指的是将数据和行为以类的形式进行封装,通过权限修饰符可以隐藏细节或控制访问的权限,从而达到权限控制的目的。
2.封装的目的
-
隐藏类的实现细节
-
让使用者只能通过事先预定的方法来访问数据,从而可以在该方法里加入控制逻辑,限制对成员变量的不合理访问。
-
可进行数据检查,从而有利于保证对象信息的完整性。便于修改,提高代码的可维护性。
-
为了实现良好的封装,需要从两个方面考虑。
-
将对象的成员变量和实现细节隐藏起来,不允许外部直接访问。
-
把方法暴露出来,让方法来控制对这些成员变量进行安全的访问和操作。
-
因此,封装实际上有两个方面的含义:把该隐藏的隐藏起来,把该暴露的暴露出来。这两个方面都需要通过使用Java提供的访问控制符来实现。
二、权限修饰符
访问权限从大到小
public(广场) protected (社区)default (家)private(自己的房间)
注意:访问控制级在子类中,是指在同一个包的子类,即内部子类,不包括外部子类。
三、标准的Java类的定义
1.普通方法
1).属性,加私有化属性
2).公有化的get,set。用来帮助私有化属性设置值以及获得值
(步骤:右键---》sources--》generate getters and setters)
3).构造器; 包括无参构造器,有参构造器。
(步骤:右键---》sources--》generate constructor using fields)
4).toString方法,用于格式化输出对象中数据。
(步骤:右键---》sources--》generatetoString)
2.快捷键
Ecilpse ait+shift+s 即可弹出source的页面,其余操作与上面同。
//人类:由多个、无数个真实存在的对象抽象而成:具备这个种类的一些共同点:外貌--行为
public class Person {
// 在类体中定义的属性和方法
//一般类中的属性都是私有化的,方法则按需定义【如果没有特殊要求,则是public】
//如果在继承关系中,父类给子类继承的属性和方法建议是public修饰
//封装是将属性及行为以类的形式封装,通过权限修饰符将该隐藏的隐藏,将该暴露的暴露【达到权限控制的目的】
// 外貌--属性--静态特征 定义一个【Person】类 中有: 名称name、性别sex、地址address的属性
//protected是在子类内部可以访问
public String name;
protected String sex;
private String address;
//name,sex,age,wealth,cash
public double wealth;
public double cash;
//提供公有化的获取及设置的方法
public void setName(String n) {
name = n;
}
public String getName() {
return name;
}
//修饰符是default
void eat() {
System.out.println("吃饭");
}
// 构造器本质是一个特殊的方法【不需要返回值类型、方法名和类名一致】
// 无参构造器
public Person() {
}
// 全参构造器:在创建对象的同时,给成员变量赋值
public Person(String n, String s, String a) {
name = n;
sex = s;
address = a;
}
}
四、static(静态与非静态)
1.什么是static
static表示的静态的意思,属于类的,当使用到这个类的时候会静态加载静态的属性以及方法。
static用于修饰变量和方法、代码块
2.静态与非静态区分
-
有static修饰的则为静态的,没有的则为非静态
-
静态的是属于类的,静态的东西是每个对象都共享的【同一个内存区域】,而非静态是属于对象的,每个对象都有一个独立的内存空间【互不干涉】
-
静态方法可以通过类名直接访问;非静态的属性和方法要通过对象访问访问
-
非静态代码块可以直接访问当前类中的非静态方法和属性。
-
静态的代码块中,不能直接访问非静态的方法和属性,除非通过对象调用。
3.使用静态与非静态的场合
工具方法、常量使用静态修饰,同一个类中共享的可以静态
定义类时的成员方法以及属性,一般就是非静态修饰
//静态与非静态
public class StaticTest {
//非静态
int num;
//静态
static int item;
public StaticTest(){
}
public StaticTest(int i,int n){
item = i;
num = n;
}
//思考:能不能在静态方法中调用非静态的方法及属性?不可以,除非创建对象,通过对象来调用【本质是内存分配】
//静态的属性及方法会在类加载时,会将其加载到内存中【静态的属于类的】
public static void main(String[] args) {
// 静态的是属于类的,在调用时可以直接加载到内存 [静态的属性和方法可以直接通过类名调用,也可以用对象来进行调用]
/*StaticTest.test();
StaticTest.item = 5;
StaticTest test = new StaticTest();
test.item = 6;//本质上也是通过类型来调用
*/
StaticTest test1 = new StaticTest(3,5);
StaticTest test2 = new StaticTest();
test2.num = 10;
System.out.println(test1.item+":"+test1.num);//3 , 5
System.out.println(test2.item+":"+test2.num);//3 , 10
test2.item = 15;
System.out.println(test1.item);//15
}
public static void test() {
System.out.println("test");
}
public void demo() {
System.out.println("test");
}
//非静态的:没有static修饰的都是为非静态的 【非静态的属于对象的】
}
五、成员变量和局部变量
1.成员变量的定义
在类中定义的变量,其中包括类变量(静态的)和实例变量(非静态的)
2.局部变量的定义
是局部有效的,通常在方法形参、方法体、代码块中定义。
局部变量分为 1.形参(在方法签名(即参数列表)中定义的变量)
2.方法局部变量(在方法内定义)
3.代码块局部变量(在代码块内定义)
3.变量初始化的时机
局部变量
默认不会初始化,在使用的时候再进行初始化
成员变量
静态成员变量(在类加载的时候初始化)
非静态的成员变量(在创建对象的时候初始化)
//交换
public class Swap {
//成员变量【类体中定义的】:类变量【静态】 实例变量 【非静态】
/*static int item;
int num;*/
//局部变量:方法体、方法的参数列表、代码块 [生命周期:在声明处到方法块末尾]
{
// System.out.println(i);//错误的
int i ;
// System.out.println(i==0);
}
static int sa ;//类变量【静态】
static int sb ;//类变量【静态】
//定义一个两数交换的方法
//swap(int a,int b) ab局部变量
public static void swap(int a,int b) {
//把数值赋值给成员变量
sa = a;
sb = b;
int item = sa;
sa = sb;
sb = item;
System.out.println("swap-a="+sa);//5
System.out.println("swap-b="+sb);//3
}
}
六、‘==’与EQUALS方法的比较
1.==
使用==是判断变量的数值是否一致
1.基本数据类型是判断数值
2.引用类型是判断对象
2.EQUALS
数组对象的equals方法是继承Object,所以是默认是==;
ctrl键放在equal函数上,点开,若没有代码,则在Eclipse中加载源码
可以通过改写equals方法实现判断对象是否相同的操作
其中:数组工具类的equals方法是重新定义的,所以可以比较数组的数值;
说明:只要是引用类型,若没有重新指定equals方法,则还是==实现判断
七、hashcode
1.什么是hashcode
hashcode主要为了提高对象判断、对象查询的效率而生成的一套机制
JVM每new一个Object,它都会将这个Object丢到一个Hash哈希表中去,这样的话,下次做 Object的比較或者取这个对象的时候,它会依据对象的hashcode再从Hash表中取这个对象。这样做的目的是提高取对象的效率。
--hashcode并不等于物理内存的地址
--equals 方法能比较两个对象的内容是否相等,因此可以用来查找某个对象是否在集合容器中,通常大致就是逐一去取集合中的每个对象元素与需要查询的对象进行equals比较,当发现某个元素与要查找的对象进行equals方法比较的结果相等时,则停止继续查找并返回肯定的信息,否则,返回否定的信息。
但是通过这种比较的方式效率很低,时间复杂度比较高。那么我们是否可以通过某种编码方式,将每一个对象都具有某个特定的码值,根据码值将对象分组然后划分到不同的区域,这样当我们需要在集合中查询某个对象时,我们先根据该对象的码值就能确定该对象存储在哪一个区域,然后再到该区域中通过equals方式比较内容是否相等,就能知道该对象是否存在集合中。【散列表的算法】
通过这种方式我们减少了查询比较的次数,优化了查询的效率同时也就减少了查询的时间。
//hashCode只是一套用于快速识别对象--判断对象是否一致的机制,不等于物理地址
//涉及到散列表的算法,散列表通过hashCode提高查找对象的效率
System.out.println(g1.hashCode());
System.out.println(g2.hashCode());
八、类加载原理以及分析
1.类加载的时机
当Java程序首次通过下面6种方式来使用某个类或接口时,系统就会初始化该类或接口。
1.创建类的实例。为某个类创建实例的方式包括:使用new操作符来创建实例,通过反射来创建实例,通过反序列化的方式来创建实例。
2.创建类的实例。为某个类创建实例的方式包括:使用new操作符来创建实例,通过反射来创建
3.访问某个类或接口的类变量,或为该类变量赋值。
4.使用反射方式来强制创建某个类或接口对应的 java.lang.Class对象。例如代码:
5.Class.forName("Person"),如果系统还未初始化 Person类,则这行代码将会导致该Person类被初始化,并返回 Person类对应的java.lang.Class对象。关于Class 的 forName方法请参考18.3节。初始化某个类的子类。当初始化某个类的子类时,该子类的所有父类都会被初始化。
6.直接使用java.exe命令来运行某个主类。当运行某个主类时,程序会先初始化该主类。
除此之外,下面的几种情形需要特别指出。
对于一个final型的类变量,如果该类变量的值在编译时就可以确定下来,那么这个类变量相当于“宏变量”。Java编译器会在编译时直接把这个类变量出现的地方替换成它的值,因此即使程序使用该静态类变量,也不会导致该类的初始化。例如下面示例程序的结果。
//测试类
public class ClassLoaderTest {
static int item = 5;
static void test() {
System.out.println("test");
}
public static void main(String[] args) {
System.out.println(1);
}
//静态初始化块,是当类加载的时候会执行
static {
System.out.println("类加载了!");
}
}
class ClassLoaderChild extends ClassLoaderTest{
}
public class ClassLoaderMain {
public static void main(String[] args) throws ClassNotFoundException {
// 1、调用类中的静态方法和属性
// ClassLoaderTest.test();
// System.out.println(ClassLoaderTest.item);
// 2、使用反射加载某个类
// Class.forName("com.day0118.ClassLoaderTest");
// 3、初始化某个类的子类
new ClassLoaderChild();
// 4、当在类中运行main方法时
}
}
总结
学习了封装的概念、权限修饰符、标准的Java类的定义、static【静态与非静态】、成员变量和局部变量、‘’==与EQUALS方法的比较、hashcode、类加载原理以及分析