static关键字的作用
static是静态的意思,可以修饰成员变量,表示给成员变量只在内存中存储一份,
可以被共享访问、修改
成员变量可以分为2类
1、静态成员变量(有static修饰,属于类,内存中加载一次):
常表示如在线人数信息、等需要被共享的信息,可以被共享访问
public class User{
//静态成员变量
public static String onlineNumber = 161;
}
访问格式:
类名.静态成员变量(推荐)
对象.静态成员变量(不推荐)
2、实例成员变量(无static修饰,存在于每个对象中):
常表示姓名name、年龄age、等属于每个对象的信息
public class User{
//静态成员变量
public static String onlineNumber = 161;
//实例成员变量
private String name;
private int age;
}
访问格式:对象.实例成员变量
public class User {
//在线人数,静态成员变量
public static int onlineNumber = 161;
//实例成员变量
private String name;
private int age;
public static void main(String[] args) {
//1.类名.静态成员变量
User.onlineNumber++;//162
//注意:同一个类中访问静态成员变量,类名可以省略不写
System.out.println(onlineNumber);//162
//2、对象.实例成员变量
//只能通过对象访问
User u1 = new User();
u1.name = "张三";
u1.age = 24;
System.out.println(u1.name + "今年" + u1.age);//张三今年24
//对象.静态成员变量(不推荐这样访问)
u1.onlineNumber++;
System.out.println(onlineNumber);//163
}
}
static修饰成员变量的内存原理
成员方法的分类:
静态成员方法(有static修饰,属于类),建议用类名访问,也可以用对象访问
实例成员方法(无static修饰,属于对象),只能用对象进行访问
使用场景:
1、表示对象自己的行为的,且方法中需要访问实例成员的,
则该方法必须申明成实例方法
2、如果该方法是以执行一个通用功能为目的,或者需要方便访问,
则可以申明成静态方法
public class Student {
private String name;
private int age;
/**
* 实例成员方法(无static修饰,属于对象),通常表示自己的行为,只能用对象进行访问
*/
public void study() {
System.out.println(name + "在好好学习,天天向上~~~");
}
/**
* 静态成员方法(有static修饰,属于类),可以被类和对象共享访问,建议用类名访问,也可以用对象访问
*/
public static void getMax(int a, int b) {
System.out.println(a > b ? a : b);
}
public static void main(String[] args) {
//1、类名.静态方法
Student.getMax(10, 20);
//注意:同一个类中,类名可以省略不写
getMax(100, 200);
//2、对象.实例方法
//study();//报错,得用对象访问
Student s = new Student();
s.name = "懒洋洋";
s.study();
//3、对象.静态方法
s.getMax(30, 10);
}
}
static修饰成员方法的内存原理
static实际应用案例:使用静态方法定义工具类
案例导学:
在企业的管理系统中,通常需要在一个系统的很多业务处使用验证码进行防刷新等安全机制
现状问题分析:
如果登录和注册等多处地方都存在验证码逻辑,就会导致同一个功能多处开发,会出现代码重复度过高
工具类
对于一些应用程序中多次需要用到的功能,可以将这些功能封装成静态方法,
放在一个类中,这个类就是工具类
工具类的作用:一是方便调用,二是提高了代码的复用
工具类原理和延伸
一次编写,处处可用
建议将工具类的构造器私有,不让工具类对外产生对象
为什么工具类中的方法不用实例方法来做?
实例方法需要创建对象调用,此时用对象只是为了调用方法,这样只会浪费内存
构造器私有也是同样道理
import java.util.Random;
public class VerifyTool {
/**
构造器私有
*/
private VerifyTool() {
}
/**
* 静态方法
*/
public static String creatCode(int n) {
//1、使用String开发验证码
String s = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
//2、定义一个变量用来存储验证码
String code = "";
Random r = new Random();
for (int i = 0; i < n; i++) {
int index = r.nextInt(s.length());
code += s.charAt(index);
}
return code;
}
}
//调用验证码这个工具类
类名.静态方法
VerifyTool.creatCode(5);
练习:定义数组工具类
//工具类
public class ArraysUtils {
/**
* 构造器私有
*/
private ArraysUtils() {
}
/**
* 静态方法
*/
public static String toString(int[] arr) {
if (arr != null) {
String result = "[";
for (int i = 0; i < arr.length; i++) {
result += (i == arr.length - 1 ? arr[i] : (arr[i] + " ,"));
}
result += "]";
return result;
} else {
return null;
}
}
public static double getAverage(int[] arr) {
//总和 最大值 最小值
int max = arr[0];
int min = arr[0];
int sum = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
if (arr[i] < min) {
min = arr[i];
}
sum += arr[i];
}
return (sum - max - min) * 1.0 / (arr.length - 2);
}
}
//使用工具类的静态方法
public class Test {
public static void main(String[] args) {
int[] arr = {10, 20, 30, 400};
System.out.println(arr);//数组的地址
System.out.println(ArraysUtils.toString(arr));//调用工具类,输出数组内容
//[10,20,30,400]
System.out.println(ArraysUtils.getAverage(arr));//调用工具类,输出25.0
int[] arr1 = null;//null
System.out.println(ArraysUtils.toString(arr1));//调用工具类,输出数组内容
int[] arr2 = {};//[]
System.out.println(ArraysUtils.toString(arr2));//调用工具类,输出数组内容
}
}
static访问注意实现:
静态方法只能访问静态的成员,不可以直接访问实例成员,但可以创建对象访问
实例方法可以访问静态的成员,也可以访问实例成员
静态方法中是不可以出现this关键字的
public class Test {
//静态成员变量
public static int onlineNumber;
//实例成员变量
private String name;
//1、静态方法的访问
public static void gerMax() {
//静态方法可以直接访问静态成员
System.out.println("访问实例成员" + Test.onlineNumber);//访问静态成员变量
//System.out.println(onlineNumber);
inAddr();//访问静态成员方法
//3、静态方法中不能出现this关键字
//System.out.println(this.name);//报错
//静态方法不能直接访问实例变量,可以创建对象进行访问
Test t = new Test();
//System.out.println(name);//报错,不能直接访问
System.out.println(t.name);//可以访问
//访问实例方法同理
t.run();//可以访问
}
//静态成员方法
public static void inAddr() {
System.out.println("访问静态成员方法成功!");
}
//2、实例方法的访问
public void run() {
//直接访问静态成员变量
System.out.println(onlineNumber);
System.out.println(Test.onlineNumber);
//直接访问实例成员变量
System.out.println(name);
sing();//访问实例方法
Test.gerMax();//访问静态方法
//gerMax();
}
public void sing() {
System.out.println("实例成员方法被访问");
}
public static void main(String[] args) {
}
}
代码块概述
代码块是类的5大成分之一(成员变量、构造器、方法、代码块、内部类),
定义在类中方法外
在Java类下,使用{}括起来的代码被称为代码块
代码块分为
1、静态代码块
格式:static{}
特点:需要通过static关键字修饰,随着类的加载而加载,
并且自动触发、只执行一次
使用场景:在类加载的时候做一些静态数据初始化的操作,以便后续使用
3、构造代码块(了解,用的少)
格式:{}
特点:每次创建对象,调用构造器执行时,都会执行该代码块中的代码,
并且在构造器执行前执行
使用场景:初始化实例资源
public class Test {
public static String schoolName;
public static void main(String[] args) {
System.out.println("-----main方法被执行-----");
System.out.println(schoolName);
}
/**
* 代码块
* 特点:与类一起加载,自动触发一次,优先被执行
* 作用:可以在程序加载时进行静态数据的初始化操作(准备内容)
*/
static {
System.out.println("---------静态初始化被触发执行--------");
schoolName = "清华大学";
}
}
public class Test {
/**
* 属于对象的,与对象一起加载,自动触发执行
*/
{
System.out.println("-----构造代码被触发执行一次------");
}
public Test() {
System.out.println("--------构造器被触发执行--------");
}
public static void main(String[] args) {
new Test();//创建对象
new Test();//创建对象
}
}
静态代码块应用案例
斗地主游戏
需求:
在启动游戏房间的时候,应提前准备好54张牌,后续才可以直接使用这些牌的数据
分析
该房间只需要一副牌
定义一个静态的ArrayList集合存储54张牌初始化好
在启动游戏房间前,应该将54张牌初始化好
当系统启动的同时需要准备好54张牌的数据,此时可以用静态代码块完成
import java.util.ArrayList;
public class Test {
//准备好放54张牌的容器
public static ArrayList<String> cards = new ArrayList<>();
//在游戏启动前将54张牌初始化好,使用静态代码块
static {
//加载54张牌
//四种花色
String[] colors = {"♥", "♣", "♠", "♦"};
//点数
String[] size = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
//先遍历点数再遍历花色
for (int i = 0; i < size.length; i++) {
for (int j = 0; j < colors.length; j++) {
cards.add(size[i] + colors[j]);
}
}
//添加大小王
cards.add("大王");
cards.add("小王");
}
public static void main(String[] args) {
System.out.println("新牌:" + cards);
}
}
什么是设计模式
设计模式是一套被前人反复使用、多数人知晓、经过分类编目的代码设计经验的总结,
后来者可以直接拿来解决问题
设计模式是软件设计中的常见解决方案,好的设计模式可以进一步的提高代码的重用性
单例模式:
可以保证系统中,应用该模式的这个类永远只有一个实例,即一个类永远只能创建一个对象
单例的场景和作用
例如任务管理器对象我们只需要一个就可以解决问题了,这样可以节省内存空间
单例模式的实现:饿汉单例模式、懒汉单例模式
饿汉单例设计模式
在用类获取对象的时候,对象已经提前创建好了
设计步骤:
定义一个类,把构造器私有
定义一个静态变量存储一个对象
//1、定义一个单例类
public class SingleInstance{
//3、定义一个静态变量存储一个对象(属于类,与类一起加载一次)
public static SingleInstance instance = new SingleInstance();
//2、单例必须私有构造器
private SingleInstance(){
System.out.println("创建了一个对象");
}
}
//调用单例饿汉模式
SingleInstance s1 = SingleInstance.instance;
懒汉单例设计模式
在真正需要该对象的时候,才去创建一个对象(延迟加载对象)
设计步骤
定义一个类,把构造器私有
定义一个静态变量存储一个对象
提供返回单例对象的方法
//1、定义一个单例类
public class SingleInstance{
//3、定义一个静态变量存储一个对象(属于类,与类一起加载一次)
public static SingleInstance instance;//null
//2、单例必须私有构造器
private SingleInstance(){
}
//必须提供一个方法返回一个单例对象
public static SingleInstance getInstance(){
...
return...;
}
}
public class Test {
public static void main(String[] args) {
SingleInstance s1 = SingleInstance.instance;
SingleInstance s2 = SingleInstance.instance;
SingleInstance s3 = SingleInstance.instance;
//同一对象,地址是一样的
System.out.println(s1);
System.out.println(s2);
System.out.println(s1==s3);//ture
}
}
//1、定义一个单例类
public class SingleInstance {
//3、定义一个静态变量存储一个对象(属于类,与类一起加载一次)
public static SingleInstance instance;//null
//2、单例必须私有构造器
private SingleInstance() {
}
//必须提供一个方法返回一个单例对象
public static SingleInstance getInstance() {
if (instance == null) {
//第一次获取对象
instance = new SingleInstance();
}
return instance;
}
}