Day13
1. private – 私有化
理解:private是访问修饰符的一种,访问修饰符规定了访问权限.
作用:
1.private修饰属性:该属性只能在类的内部使用
2.private修饰方法:该方法只能在类的内部使用
应用场景:不让让外界访问的属性和方法就用private修饰
public class A {
private String str = "好好学习";
private void method01(){
System.out.println("aaabbbccc -- " + str);
}
public void method02(){
method01();
}
}
public class Test01 {
public static void main(String[] args) {
A a = new A();
a.method02();
}
}
2. 封装
面向对象三大特征之一: 封装,继承,多态
理解:不能直接操作属性,可以添加get/set方法
*对象代表什么,就得封装对应的数据,并提供数据对应的行为*
步骤:
1.私有化属性: 成员变量使用private
2.添加get-获取/set-设置方法
好处:外界不能直接操作属性(有风险),通过get/set方法操作属性,可以在方法内添加额外的功能
将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问
思考题:操作属性有什么功能?
1.设置属性 – set
2.获取属性 – get
set 存 get 取 先存后取,在set中做判断等操作
需求:模拟银行用户操作余额的功能
分析:
操作余额(存钱、取钱、查看)
import java.time.LocalDateTime;
public class User {
String username;
String password;
String name;
private double surplus;//余额
public User() {
}
public User(String username, String password, String name, double surplus) {
this.username = username;
this.password = password;
this.name = name;
this.surplus = surplus;
}
//设置余额
public void setSurplus(double surplus){
//额外的功能
double num = (surplus - this.surplus);
System.out.println(LocalDateTime.now() + " -- " + this.name + "用户操作了金额:" + ((num>0)?"+":"") + num); //显示当前时间
//设置属性
this.surplus = surplus;
}
//获取余额
public double getSurplus(){
//额外的功能
System.out.println(LocalDateTime.now() + " -- " + this.name + "用户获取了金额");
//返回余额
return surplus;
}
}
public class Test01 {
public static void main(String[] args) {
User user = new User("1445584980", "123123", "小彭", 2000);
//存钱
//user.surplus = user.surplus+200;
user.setSurplus(user.getSurplus() + 200);
//取钱
//user.surplus = user.surplus-1800;
user.setSurplus(user.getSurplus() -1800);
//查看
//System.out.println(user.surplus);//400.0
System.out.println(user.getSurplus());//400.0
}
}
运行结果:
3. this
概念:表示本对象
理解:哪个对象调用该方法,该方法里的this就表示该对象
作用:
1.this.属性:调用本对象的成员属性
2.this.方法:调用本对象的成员方法
3.this():在构造方法的第一句调用本类另外的构造方法
问题: 成员变量何时在内存中存在? 静态变量何时在内存中存在?
成员变量在创建对象时。静态变量在类创建时就有
成员变量会在对象被创建时分配内存并存在于对象的内存空间中;静态变量在类加载时被初始化,此时就会在内存中分配空间
import java.time.LocalDateTime;
public class User {
private String username;
private String password;
private String name;
private double surplus;//余额
public User() {
//在当前构造方法中调用另一个构造方法
this("默认账号", "默认密码", "亚当", 0.0);
}
public User(String username, String name, String phone, char sex, double surplus) {
//在当前构造方法中调用另一个构造方法
this(username,"000000", name, phone, sex, surplus);
}
public User(String username, String password, String name, double surplus) {
this.username = username;
this.password = password;
this.name = name;
this.surplus = surplus;
}
//设置余额
public void setSurplus(double surplus){
//额外的功能
double num = (surplus - this.surplus);
System.out.println(LocalDateTime.now() + " -- " + this.name + "用户操作了金额:" + ((num>0)?"+":"") + num);
//设置属性
this.surplus = surplus;
}
//获取余额
public double getSurplus(){
//额外的功能
System.out.println(LocalDateTime.now() + " -- " + this.name + "用户获取了金额");
//返回余额
return surplus;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 转账
* @param username 对方的账号
* @param money 转账的金额
*/
public void transferAccounts(String username,double money){
//获取本对象的余额,判断是否比转账的金额更多
if(this.getSurplus() > money){
//将当前用户的余额的money部分转给对方账号
//this.setSurplus(this.getSurplus()-money);
setSurplus(getSurplus()-money);
System.out.println("已经给" + username + "转账成功");
}else{
System.out.println("余额不足");
}
}
}
public class Test01 {
public static void main(String[] args) {
// User user = new User("1445584980", "123123", "小彭", 2000);
// user.transferAccounts("12345678999", 800);
}
}
4. static修饰属性
概念:
1.成员属性:每个对象独享一份
2.静态属性:每个对象共享一份
3.静态属性何时创建?
使用到类,JVM会判断方法区中是否有该类的class文件,如果没有,就把该类的class文件加载到方法区
JVM会扫描该类的所有属性,并把属性添加到静态区中(1.开辟空间 2.赋系统的默认值)
4.静态属性何时销毁?
项目结束时,静态属性才会被销毁,所以静态属性的生命周期很长,项目中使用时需警慎
5.静态属性的应用场景?
该类所有的对象需要共享的属性,就可以设置为静态
注意:静态属性属于类的属性,直接使用类名调用。使用对象调用会出现警告
静态属性比成员属性更早的在内存中存在
public class A {
//成员属性
String str1;
//静态属性
static String str2;
}
public class Test01 {
public static void main(String[] args) {
A a1 = new A();
A a2 = new A();
a1.str1 = "aaa";
a2.str1 = "bbb";
System.out.println(a1.str1);//aaa
System.out.println(a2.str1);//bbb
//注意:静态属性属于类的属性,直接使用类名调用。使用对象调用会出现警告
// a1.str2 = "xxx";
// a2.str2 = "yyy";
// System.out.println(a1.str2);//yyy
// System.out.println(a2.str2);//yyy
A.str2 = "xxx";
A.str2 = "yyy";
System.out.println(A.str2);//yyy
System.out.println(A.str2);//yyy
}
}
注意:A.str2不是xxx,而是yyy
由于静态属性存在静态区,其属性不允许重复,不同调用赋值会覆盖掉
static修饰属性内存图:
5.static修饰方法
成员方法 vs 静态方法 应用场景
成员方法:必须使用对象调用,也就是说调用成员方法之前必须创建对象(开辟空间)
静态方法:属于类的方法,直接使用类名调用,纯功能的方法就可以设计成静态方法(工具类),比如MyArrays
需求:模仿Java的MyArrays,编写自己的MyMyArrays
目的:
1.掌握工具类的概念
2.回顾之前的知识点
3.理解文档注释的作用
/**
* 自己编写的数组工具类
* @author 小彭
* @version 1.0
*/
public class MyArrays {
/**
* 数组的排序
* @param a 目标数组
*/
public static void sort(int[] a){
for (int i = 0; i < a.length-1; i++) {
for (int j = 0; j < a.length-1-i; j++) {
if(a[j] > a[j+1]){
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
}
/**
* 数组的查找,必须先排序,在查找
* @param a 目标数组
* @param key 需要查找的元素
* @return 如果搜索的元素包含在数组中就返回元素的下标; 否则,返回(-插入点-1)
*/
public static int binarySearch(int[] a,int key){
int start = 0;
int end = a.length-1;
while(start <= end){
int mid = (start+end)/2;
if(key < a[mid]){
end = mid-1;
}else if(key > a[mid]){
start = mid+1;
}else{
return mid;
}
}
return -start-1;
}
/**
* 拷贝数组
* @param original 目标数组
* @param newLength 新数组的长度
* @return 新数组
*/
public static int[] copyOf(int[] original, int newLength){
int copyLength = original.length;
if(copyLength > newLength){
copyLength = newLength;
}
int[] newArr = new int[newLength];
for (int i = 0; i < copyLength; i++) {
newArr[i] = original[i];
}
return newArr;
}
/**
* 拷贝区间数组
* @param original 目标数组
* @param from 开始下标-包含
* @param to 结束下标 - 排他
* @return 新数组
*/
public static int[] copyOfRange(int[] original, int from, int to){
int newLength = to-from;
int[] newArr = new int[newLength];
int index = 0;
for (int i = from; i < to; i++) {
newArr[index++] = original[i];
}
return newArr;
}
/**
* 替换全部元素
* @param a 目标数组
* @param val 替换的值
*/
public static void fill(int[] a, int val){
fill(a, 0, a.length, val);
}
/**
* 替换区间元素
* @param a 目标数组
* @param fromIndex 开始下标 - 包含
* @param toIndex 结束下标 - 排他
* @param val 替换的值
*/
public static void fill(int[] a, int fromIndex, int toIndex, int val){
for (int i = fromIndex; i < toIndex; i++) {
a[i] = val;
}
}
/**
* 将数组转换为字符串
* @param a 目标数组
* @return 转换后的字符串
*/
public static String toString(int[] a){
String str = "[";
for (int element : a) {
if(str.length() != 1){
str += ",";
}
str += element;
}
str += "]";
return str;
}
}
import com.qf.array.MyArrays;
public class Test01 {
public static void main(String[] args) {
int[] arr = {18,32,81,63,20,9};
//排序 - [9, 18, 20, 32, 63, 81]
MyArrays.sort(arr);
//查找(底层还用二分法去查找元素,所以必须先排序,再查找!)
//返回值规则:如果搜索的元素包含在数组中就返回元素的下标; 否则,返回(-插入点-1)
int index = MyArrays.binarySearch(arr, 28);
System.out.println("查找元素的下标为:" + index);
//拷贝数组(目标数组,新的长度)- [9, 18, 20, 32, 63, 81, 0, 0, 0, 0]
int[] copyOf = MyArrays.copyOf(arr, 10);
//拷贝区间数组(目标数组,开始下标-包含,结束下标-排他)- [18, 20, 32, 63, 81, 0, 0]
int[] copyOfRange = MyArrays.copyOfRange(copyOf, 1, 8);
//替换元素 - [666, 666, 666, 666, 666, 666, 666]
MyArrays.fill(copyOfRange, 666);
//替换区间元素(目标数组,开始下标-包含,结束下标-排他,替换的值) - [666, 666, 888, 888, 888, 666, 666]
MyArrays.fill(copyOfRange, 2, 5, 888);
//将数组转换为字符串
String str = MyArrays.toString(copyOfRange);
System.out.println(str);
}
6. 静态代码块
静态代码块是类加载到方法区时才会被调用,该代码块只能初始化静态变量
代码块是创建对象时优先于构造方法调用,该代码块可以初始化成员变量和静态变量()
构造方法是创建对象时调用,该方法可以初始化成员变量和静态变量
经验:
1.创建对象时,在构造方法中初始化数据
2.项目中可以在静态代码块中初始化静态属性
public class A {
String str1;//成员属性
static String str2;//静态属性
//静态代码块:class文件加载到方法区时调用
//作用:操作静态属性,不能操作成员属性
static{
A.str2 = "eee";//底层实现:A.str2 = "eee";
System.out.println("静态代码块 --" + A.str2);
}
//代码块:创建对象时优先于构造方法调用
//作用:操作成员属性和静态属性
{
str1 = "ccc";//底层实现:this.str1 = "ccc";
str2 = "ddd";//底层实现:A.str2 = "ddd";
System.out.println("代码块-- " + str1 + " -- " + str2);
}
//构造方法:创建对象时调用构造方法
//作用:操作成员属性和静态属性
public A() {
str1 = "aaa";//底层实现:this.str1 = "aaa";
str2 = "bbb";//底层实现:A.str2 = "bbb";
System.out.println("构造方法 -- " + str1 + " -- " + str2);
}
}
public class Test01 {
public static void main(String[] args) {
A a1 = new A();
A a2 = new A();
}
}
思考题:什么算使用到该类了?
1.新建一个类的对象
2.调用该类的静态属性
3.调用该类的静态方法
4.Class.forName(“java.lang.String”)
7.分包
基本作用:防止了类的重名问题
项目作用:项目中有众多的类,把相同功能的类放在同一个包中,方便管理
工具类:com.dream.util/tool
实体类:com.dream.vo/bean/entity/bto/pojo
数据库类:com.dream.dao/mapper
包名的命名规范
路径名.路径名.xxx.xxx
例如:com.pcb.Work
8. 导出jar包
1.项目右键,选择 Export,然后选择java下的 JAR file (java项目选择JAR,web项目上线选择WAR)
2.选择路径(桌面)
3.桌面上出现JAR图标
9. 导入JAR包
1.项目右键选择Folder,新建一个文件夹,名为lib
2.将需要的JAR包放在lib文件夹中
3.右键选择Build path ,建立链接
10.导出API
1.项目右键选择Export ,选择Javadoc
2.选择jdk中的javadoc.exe,然后选择存放路径桌面(注意:生成的是一个一个页面,所有在桌面后面加一个UtilsAPI文件夹)
3.等待生成
4.怎么找–打开文件夹,选择index.html,就可以了
补
static存在的主要意义
static的主要意义是在于创建独立于具体对象的变量或者方法。以致于即使没有创建对象,也能使用属性和调用方法!
static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。
为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。
static的独特之处
1、被static修饰的变量或者方法是独立于该类的任何对象,也就是说,这些变量和方法不属于任何一个实例对象,而是被类的实例对象所共享。 就是说,一个类的静态成员,它是属于大伙的【大伙指的是这个类的多个对象实例,我们都知道一个类可以创建多个实例!】,所有的类对象共享的,不像成员变量是自个的【自个指的是这个类的单个实例对象】
2、在该类被第一次加载的时候,就会去加载被static修饰的部分,而且只在类第一次使用时加载并进行初始化,注意这是第一次用就要初始化,后面根据需要是可以再次赋值的。
3、static变量值在类加载的时候分配空间,以后创建类对象的时候不会重新分配。赋值的话,是可以任意赋值的!
4、被static修饰的变量或者方法是优先于对象存在的,也就是说当一个类加载完毕之后,即便没有创建对象,也可以去访问。
static注意事项
1.静态只能访问静态。
2.非静态既可以访问非静态的,也可以访问静态的
简答题
1.面向对象特征
封装:一是为了代码的高内聚低耦合,再是为了数据的安全性
继承:子类可以继承父类的属性和方法,并可以扩展自己的属性方法
多态:首先要有继承,重写,然后父类的引用可以指向多个不同子类对象。多态分为编译时多态和运行时多态,方法重载就是编译时多态的体现,方法重写就是运行时多态的体现。
12. 总结
1.private关键字 – 私有化
修饰属性:属性不能被外界访问
修饰方法:方法不能被外界访问
2.封装
步骤:
1.私有化属性
2.get/set方法注意:理解封装的概念
3.面相对象版本的五子棋
a.私有化属性的业务场景
b.私有化方法的业务场景
c.状态码 – play方法的返回值
4.static
a.修饰属性
b.修饰方法(注重MyArrays,导出Jar包、导入Jar包、导出API)
c.静态代码块