JAVA基础07-封装,类加载原理以及分析(内有练习代码)

2024-04-17 01:12

本文主要是介绍JAVA基础07-封装,类加载原理以及分析(内有练习代码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

封装的理解

概念

目的

权限修饰符

访问权限从大到小

如何快速定义一个标准的Java类

1.普通方法

2.快捷键

练习

static

定义

静态与非静态区分

使用静态与非静态的场合

成员变量和局部变量

成员变量

局部变量

例子讲解:两数交换

解决方法

变量的初始化时机

局部变量

成员变量

==与equals方法

==

equals

改写例子

什么是hashcode

类加载原理以及分析

类加载的时机


封装的理解

概念

(面向对象的三大特征之一)将数据和行为以类的形式进行封装,通过权限修饰符可以隐藏细节或控制访问的权限,从而达到权限控制的目的。

目的

1.隐藏类的实现细节

2.让使用者只能通过事先预定的方法来访问数据,从而可以在该方法里加入控制逻辑限制对成员变量的不合理访问

3.可进行数据检查,从而有利于保证对象信息的完整性。便于修改,提高代码的可维护性

4.为了实现良好的封装,需要从两个方面考虑。

①将对象的成员变量和实现细节隐藏起来,不允许外部直接访问。

②把方法暴露出来,让方法来控制对这些成员变量进行安全的访问和操作。

因此,封装实际上有两个方面的含义:把该隐藏的隐藏起来,把该暴露的暴露出来。这两个方面都需要通过使用Java提供的访问控制符来实现。


权限修饰符

访问权限从大到小

public(广场) protected (社区)default (家)private(自己的房间)

注意:访问控制级在子类中,是指在同一个包的子类,即内部子类,不包括外部子类。


如何快速定义一个标准的Java类

1.普通方法

①属性,加私有化属性

②公有化的get,set。用来帮助私有化属性设置值以及获得值 

(步骤:右键---》sources--》generate getters and setters)

③构造器; 包括无参构造器,有参构造器。

(步骤:右键---》sources--》generate constructor using fields)

④toString方法,用于格式化输出对象中数据

(步骤:右键---》sources--》generatetoString)

public class Student {//学号、姓名、性别、年龄//1、私有化的属性private String code;private String name;private String sex;private int age;//2、公有化的get、set方法public String getCode() {return code;}public void setCode(String code) {this.code = code;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}//3、构造器【无参的、有参的】public Student(String code, String name, String sex, int age) {super();this.code = code;this.name = name;this.sex = sex;this.age = age;}public Student() {super();}// 4、toString方法:作用:方便输出查看对象数据@Overridepublic String toString() {return "Student [code=" + code + ", name=" + name + ", sex=" + sex + ", age=" + age + "]";}
}
 

2.快捷键

 alt+shift+s 即可弹出source的页面,其余操作与上面同。


练习

1.定义标准的医生类:id、name、subject、sex

定义方法:check方法,检查病人,入参Person的对象

 方法操作为输出病人的个人信息

 思路:定义Doctor类(标准的java类)--属性--方法,person类,再实例测试。

//医生类
public class Doctor {// 1、私有化属性id、name、subject、sexprivate int id;private String name;private String subject;private String sex;//定义方法:check方法,检查病人,入参Person的对象 方法操作为输出病人的个人信息public void check(Person p) {System.out.println("病人姓名:"+p.name+"性别:"+p.sex);}// 2、get、setpublic int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSubject() {return subject;}public void setSubject(String subject) {this.subject = subject;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}// 3、构造器public Doctor(int id, String name, String subject, String sex) {super();this.id = id;this.name = name;this.subject = subject;this.sex = sex;}public Doctor() {super();}// 4、toString@Overridepublic String toString() {return "Doctor [id=" + id + ", name=" + name + ", subject=" + subject + ", sex=" + sex + "]";}
}
//人类:由多个、无数个真实存在的对象抽象而成:具备这个种类的一些共同点:外貌--行为
public class Person {// 在类体中定义的属性和方法//一般类中的属性都是私有化的,方法则按需定义【如果没有特殊要求,则是public】//如果在继承关系中,父类给子类继承的属性和方法建议是public修饰//封装是将属性及行为以类的形式封装,通过权限修饰符将该隐藏的隐藏,将该暴露的暴露【达到权限控制的目的】// 外貌--属性--静态特征 定义一个【Person】类 中有: 名称name、性别sex、地址address的属性//protected是在子类内部可以访问public String name;protected String sex;private String address;//name,sex,age,wealth,cashpublic double wealth;public double cash;//提供公有化的获取及设置的方法public void setName(String n) {name = n;}public String getName() {return name;}//修饰符是defaultvoid eat() {System.out.println("吃饭");}// 构造器本质是一个特殊的方法【不需要返回值类型、方法名和类名一致】public Person() {// 无参构造器}public Person(String n, String s, String a) {// 全参构造器:在创建对象的同时,给成员变量赋值name = n;sex = s;address = a;}
}

2.银行类:属性{name,adress,totalwealth}--提取现金的方法bank

person:属性{name,sex,age,wealth,cash}

思路与练习1同,练习1的测试与练习二的测试相类似。

//银行类
public class Bank {// name,adress,totalwealthprivate String name;private String adress;private double totalwealth;//--提取现金的方法bankpublic void drawMoney(Person p,double money) {//银行总财富减少totalwealth = totalwealth-money;//人现金流增加p.cash = p.cash+money;//System.out.println(p.name+"成功取款:"+money);}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAdress() {return adress;}public void setAdress(String adress) {this.adress = adress;}public double getTotalwealth() {return totalwealth;}public void setTotalwealth(double totalwealth) {this.totalwealth = totalwealth;}public Bank(String name, String adress, double totalwealth) {super();this.name = name;this.adress = adress;this.totalwealth = totalwealth;}public Bank() {super();}@Overridepublic String toString() {return "Bank [name=" + name + ", adress=" + adress + ", totalwealth=" + totalwealth + "]";}
}

static

定义

static表示的静态的意思,属于类的,当使用到这个类的时候会静态加载静态的属性以及方法。

static用于修饰变量和方法、代码块

静态与非静态区分

1.有static修饰的则为静态的,没有的则为非静态

2.静态的是属于类的,静态的东西是每个对象都共享的【同一个内存区域

非静态是属于对象的,每个对象都有一个独立的内存空间【互不干涉】

3.静态方法可以通过类名直接访问;非静态的属性和方法要通过对象访问访问

4.非静态代码块可以直接访问当前类中的非静态方法属性

静态的代码块中,不能直接访问非静态的方法和属性,除非通过对象调用。

使用静态与非静态的场合

工具方法、常量使用静态修饰,同一个类中共享的可以静态 

定义类时的成员方法以及属性,一般就是非静态修饰

//静态与非静态
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) {// 静态的是属于类的,在调用时可以直接加载到内存  //[静态的属性和方法可以直接通过类名调用,也可以用对象来进行调用]//非静态的:没有static修饰的都是为非静态的 【非静态的属于对象的】test();item=5;//静态的直接调用(内部类,属性)StaticTest.test();//若为外部类,则以这种形式  例子:Arrays.toString() (类.方法名直接调用)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  ,  5System.out.println(test2.item+":"+test2.num);//3  ,  10//num非静态,每个对象值不同。test2.item = 15;System.out.println(test1.item);//结果为15 ,与对象没关系,item是个静态即属于类。}public static void test() {System.out.println("test");}public void demo() {//不能在main(为静态)中,即静态的方法中直接引用,得创建对象来调用。System.out.println("test");}}

成员变量和局部变量

成员变量

在类中定义的变量,其中包括变量(静态的)和实例变量(非静态的)

局部变量

是局部有效的,通常在方法形参方法体代码块中定义。

分为1.形参(在方法签名(即参数列表)中定义的变量)

2.方法局部变量(在方法内定义)

3.代码块局部变量(在代码块内定义)

例子讲解:两数交换

public class Swap {	//定义一个两数交换的方法//swap(int a,int b) ab局部变量public static void swap(int a,int b) {int item = a;a = b;b = item;System.out.println("swap-a="+a);//5System.out.println("swap-b="+b);//3}public static void main(String[] args) {//局部变量int a = 3;int b = 5;swap(a,b);//调用了交换方法,但值却没发生变化。System.out.println("main-a="+a);//3System.out.println("main-b="+b);//5}}
 

 

解决方法

从以下两个角度解决两数交换,值却交换不了的问题。

1、没有交换同一个变量【成员变量】

public class Swap {//解决方法一:成员变量(静态,非静态都可以,只是调用方法不同)int sa ;int sb ;//定义一个两数交换的方法public  void swap(int a,int b) {sa=a;sb=b;int item = sa;sa = sb;sb = item;}public static void main(String[] args) {Swap s1=new Swap();//sa,sb变量,swap()方法为非静态成员,因此需要创建一个新的对象来调用方法与赋值s1.swap(3, 5);System.out.println("main-a="+s1.sa);//5System.out.println("main-b="+s1.sb);//3}}
 

2、问题:没有返回值【增加一个返回值--数组】

public class Swap {//解决方法二:增加一个返回值(数组返回值)	//定义一个两数交换的方法public  static  int[] swap(int a,int b) {//返回一个int[]数组int item = a;a = b;b = item;return new int[] {a,b};}public static void main(String[] args) {int a=3;int b=5;int[] res=swap(a,b);//静态,直接调用swap方法a=res[0];//赋值b=res[1];System.out.println("main-a="+a);//5System.out.println("main-b="+b);//3}
}

变量的初始化时机

局部变量

默认不会初始化,在使用的时候再进行初始化

成员变量

静态成员变量(在类加载的时候初始化)

非静态的成员变量(在创建对象的时候初始化)


==与equals方法

==

使用==是判断变量的数值是否一致

1.基本数据类型(八大数据类型)是判断数值

2.引用类型是判断对象

比较内存中的存放地址(堆地址),同个new出来的对象才是true

equals

数组对象的equals方法是继承Object,所以是默认是==;

在不重写的情况下,默认比较地址值,但一般情况下JMM会自动重写·重写后,比较两个对象的内容是否相等。

ctrl键放在equal函数上,点开,若没有代码,则在Eclipse中加载源码

源码:

可以通过改写equals方法实现判断对象是否相同的操作

其中:数组工具类的equals方法是重新定义的,所以可以比较数组的数值;

说明:只要是引用类型,若没有重新指定equals方法,则还是==实现判断


改写例子

public class ItGay {private String name;private String sex;private int age;//改写比较方法@Overridepublic boolean equals(Object obj) {//1、当对象一致,则数值肯定一致if(this==obj) {return true;}if(this.hashCode()==obj.hashCode()) {return true;}//比较对象中的数值是否完全相等ItGay obj2 = (ItGay) obj;//if(!name.equals(obj2.name)) {//namereturn false;}if(!sex.equals(obj2.sex)) {//sexreturn false;}if(age!=obj2.age) {//agereturn false;}//数值都相同,则返回truereturn true;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public ItGay(String name, String sex, int age) {super();this.name = name;this.sex = sex;this.age = age;}public ItGay() {super();}/*@Overridepublic String toString() {return "ItGay [name=" + name + ", sex=" + sex + ", age=" + age + "]";}*/
}
//测试类
public class ItGayTest {public static void main(String[] args) {// 创建对象ItGay g1 = new ItGay("tom", "男", 48);ItGay g2 = new ItGay("tom", "男", 48);//使用==比较引用类型时,实际是比较对象是否一致【客观】System.out.println(g1==g2);System.out.println(g1.equals(g2));//实质上是使用Object中的equals【默认使用==】//当两个对象的数值完全相同时,则主观认为两个对象是同一个对象【主观】,重写equal方法}}

什么是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());

类加载原理以及分析


类加载的时机

当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基础07-封装,类加载原理以及分析(内有练习代码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/910408

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于