static关键字的概述
/**
目标:static关键字的概述。(重点)
引入:
我们之前定义了很多成员变量(name , age , sex)
其实我们只写了一份,但是发现每个对象都可以用,就说明
Java中这些成员变量或者方法是存在所属性的。
有些是属于对象的,有些是属于类本身的。
Java是通过成员变量是否有static修饰来区分是类的还是属于对象的。
static == 静态 == 修饰的成员(方法和成员变量)属于类本身的。
按照有无static修饰,成员变量和方法可以分为:
成员变量:
(1)静态成员变量(类变量):
有static修饰的成员变量称为静态成员变量也叫类变量,属于类本身的,
直接用类名访问即可。
(2)实例成员变量
无static修饰的成员变量称为实例成员变量,属于类的每个对象的,
必须用类的对象来访问。
成员方法:
(1)静态方法
有static修饰的成员方法称为静态方法也叫类方法,属于类本身的,
直接用类名访问即可。
(2)实例方法
无static修饰的成员方法称为实例方法,
属于类的每个对象的,必须用类的对象来访问。
小结:
成员变量有2种
-- 有static修饰的属于类叫静态成员变量,与类一起加载一次,直接用类名调用即可。
-- 无static修饰的属于类的每个对象的叫实例成员变量,
与类的对象一起加载,对象有多少个,实例成员变量就加载多少份。必须用类的对象调用。
成员方法有2种:
-- 有static修饰的属于类叫静态方法,直接用类名调用即可。
-- 无static修饰的属于类的每个对象的叫实例方法,必须用类的对象调用。
*/
public class StaticDemo01 {
}
成员变量的分类和访问
/**
目标:成员变量的分类和访问。
按照有无static修饰成员变量分为:
(1)静态成员变量:有static修饰,属于类本身与类一起加载一次,直接用类名访问即可。
(2)实例成员变量:无static修饰,属于类的每个对象的,必须先创建对象,再用对象来访问。
成员变量的访问语法:
静态成员变量访问:
类名.静态成员变量。
对象.静态成员变量。(不推荐)
实例成员变量的访问:
对象.实例成员变量。
小结:
静态成员变量有static修饰,属于类本身,与类加载一次,因为只有一份所以可以被类和类的对象共享访问。
注意:不建议用对象访问静态成员变量,静态成员变量直接用类名访问即可!!!
实例成员变量,无static修饰,属于类的对象的,必须先创建对象,然后用对象来访问!
*/
public class Student{
// 1.静态成员变量:有static修饰,属于类本身,直接用类名访问即可!
public static String schoolName = "黑马";
// 2.实例成员变量:无static修饰,属于类的对象的,必须用对象访问!
private String name;
private int age ;
public static void main(String[] args) {
// 1.类名.静态成员变量
System.out.println(Student.schoolName);
// 注意:同一个类中访问静态成员变量可以省略类名不写
System.out.println(schoolName);
// 2.对象.实例成员变量
//System.out.println(Student.name); // 报错!
Student swk = new Student();
swk.name = "孙悟空";
System.out.println(swk.name);
System.out.println(swk.age);
// 3.对象.静态成员变量(不推荐)
// 静态成员变量属于类,直接用类名访问即可。
System.out.println(swk.schoolName);
}
}
成员方法的分类和访问
/**
目标:成员方法的分类和访问。
成员方法按照有无static修饰可以分为:
(1)静态方法:有static修饰,属于类,直接用类名访问即可。
(2)实例方法:无static修饰,属于对象的,必须用对象来访问。
成员方法的访问语法:
静态方法的访问格式:
类名.静态方法
对象.静态方法(不推荐)
实例方法的访问格式:
对象.实例方法
小结:
静态方法属于类,有static修饰,直接用类名访问即可。
实例方法属于对象,无static修饰,必须先创建对象,然后用对象来访问。
静态方法也可以被对象共享访问,但是不推荐,因为静态方法直接用类名访问即可。
*/
public class Student {
// 0.实例成员变量。
private String name;
private int age ;
// 1.静态方法:有static修饰,属于类,直接用类名访问即可!
public static void inAddr(){
System.out.println("我们都在天河区吉山村happy的学习Java!");
}
// 2.实例方法:无static修饰,属于对象,必须用对象访问!
public void eat(){
System.out.println(name + "已经"+age+"岁,在吃好吃的!!");
}
public static void main(String[] args) {
// a.类名.静态方法
Student.inAddr();
// 注意:在同一个类中访问静态成员可以省略类名不写!!
inAddr();
// b.对象.实例方法
// Student.eat(); // 报错了!
Student zbj = new Student();
zbj.name = "猪刚鬣";
zbj.age = 1000;
zbj.eat();
// c.对象.静态方法(不推荐)
zbj.inAddr();
}
}
成员变量和成员方法访问的拓展(面试常考)
/**
拓展:成员变量和成员方法访问的拓展。(面试常考)
方法:实例方法,静态方法。
成员变量:实例成员变量,静态成员变量。
8种访问形式的问答:
a.实例方法是否可以直接访问实例成员变量?可以的,因为它们都属于对象。
b.实例方法是否可以直接访问静态成员变量?可以的,静态成员变量可以被共享访问。
c.实例方法是否可以直接访问实例方法? 可以的,实例方法和实例方法都属于对象。
d.实例方法是否可以直接访问静态方法?可以的,静态方法可以被共享访问!
--------------------------------------------------------------------
a.静态方法是否可以直接访问实例变量? 不可以的,实例变量必须用对象访问!!
b.静态方法是否可以直接访问静态变量? 可以的,静态成员变量可以被共享访问。
c.静态方法是否可以直接访问实例方法? 不可以的,实例方法必须用对象访问!!
d.静态方法是否可以直接访问静态方法?可以的,静态方法可以被共享访问!!
*/
public class MethodFieldDemo {
// 静态成员变量
public static String schoolName = "黑马";
// 实例成员变量
private String name;
// 静态方法
public static void test(){
// run(); // 报错了
}
// 实例方法
public void run(){
}
// 实例方法
public void eat(){
run();
test();
System.out.println(name);
System.out.println(schoolName);
}
}
代码块
代码块-静态代码块
import java.util.ArrayList;
/**
目标:代码块-静态代码块。
代码块是类的成分之一:
成员变量,方法,构造器,代码块,内部类。
代码块按照有无static修饰分为:
1.静态代码块。
2.实例代码块。
静态代码块的格式:
static {
}
静态代码块特点:
-- 必须有static修饰。
-- 会与类一起优先加载,且自动触发执行一次。
静态代码块作用:
-- 可以在执行类的方法等操作之前先在静态代码块中进行静态资源的初始化操作。
小结:
静态代码块有static修饰,与类一起加载,自动触发执行一次。
静态代码块的作用:可以用于在静态代码块中进行静态资源的初始化操作。
*/
public class CodeDemo01 {
public static String schoolName ;
public static ArrayList<String> lists = new ArrayList<>();
// 静态代码块,属于类,与类一起加载一次!
static {
System.out.println("静态代码块被触发执行~~~~~~~");
// 在静态代码块中进行静态资源的初始化操作
schoolName = "黑马";
lists.add("3");
lists.add("4");
lists.add("5");
}
public static void main(String[] args) {
System.out.println(schoolName);
System.out.println(lists);
}
}
代码块-实例代码块
import java.util.ArrayList;
/**
目标:代码块-实例代码块。
实例代码块的格式:
{
}
实例代码块的特点:
-- 无static修饰。
-- 会与类的对象一起加载,每次创建类的对象的时候,
实例代码块都会被加载且自动触发执行一次。
-- 实例代码块的代码在底层实际上是提取到每个构造器中去执行的!
实例代码块的作用:
-- 实例代码块可以在创建对象之前进行实例资源的初始化操作。
小结:
实例代码块无static修饰,属于对象,与对象一起加载执行。
实例代码块的代码在底层实际上是提取到每个构造器中去执行的!
实例代码块可以在创建对象之前进行实例资源的初始化操作。
*/
public class CodeDemo02 {
private String name;
private ArrayList<String> lists = new ArrayList<>();
// 实例代码块!属于对象!与对象一起加载!
{
name = "小手";
lists.add("东");
lists.add("南");
lists.add("西");
lists.add("北");
System.out.println("实例代码块被触发执行一次~~~~~~~~");
}
public CodeDemo02(){
}
public CodeDemo02(String name){
}
public static void main(String[] args) {
CodeDemo02 c = new CodeDemo02();
System.out.println(c.name);
System.out.println(c.lists);
new CodeDemo02();
new CodeDemo02();
}
}
final关键字
/**
目标:final关键字。
final是最终的含义。
final用于修饰:类,方法,变量。
1.final修饰类,类不能被继承了。
2.final可以修饰方法,方法就不能被重写了。
3.final修饰变量总规则:变量有且仅能被赋值一次。
拓展:final和abstract的关系?
互斥关系,不能同时修饰类或者同时修饰方法!!
*/
public class FinalDemo01 {
public static void main(String[] args) {
}
}
class Animal{
public final void run(){
}
}
class Cat extends Animal{
// @Override
// public void run(){
//
// }
}
// final修饰类,类不能被继承了。
//final class Animal{
//
//}
//class Cat extends Animal{
//
//}
/**
目标:final修饰变量-局部变量。
final修饰变量的总规则:有且仅能被赋值一次。
变量有几种?
成员变量
-- 静态成员变量:有static修饰,属于类,只加载一份。
-- 实例成员变量:无static修饰,属于每个对象,与对象一起加载。
局部变量
-- 只能方法中,构造器中,代码块中,for循环中,用完作用范围就消失了。
final修饰局部变量:
-- 让值被固定或者说保护起来,执行的过程中防止被修改。
*/
public class FinalDemo02 {
public static void main(String[] args) {
final int age = 12; // 第一次赋值
// age = 20; // 第二次赋值,报错!
final double r = 3.14;
//r = 12.3;
buy(0.8);
}
public static void buy(final double rate){
//rate = 0.7; // 第二次赋值! ,报错!
}
}
/**
目标:final修饰静态成员变量。
final修饰变量的总规则:有且仅能被赋值一次。
final修饰静态成员变量,变量变成了常量。
常量:有public static final修饰,名称字母全部大写,多个单词用下划线连接。
拓展:
final修饰静态成员变量可以在哪些地方赋值一次:
1.定义的时候赋值一次。
2.可以在静态代码块中赋值一次。
*/
public class FinalDemo03 {
// 常量:有public static final修饰,名称字母全部大写,多个单词用下划线连接。
public static final String SCHOOL_NAME = "黑马" ;
public static final String SCHOOL_NAME1 ;
static{
SCHOOL_NAME1 = "黑马1";
//SCHOOL_NAME1 = "黑马2"; // 报错,第二次赋值!
}
}
/**
目标:final修饰实例成员变量。(了解。用不到)
final修饰变量的总规则:有且仅能被赋值一次。
拓展:
final修饰实例成员变量可以在哪些地方赋值1次:
1.定义的时候赋值一次。
2.可以在实例代码块中赋值一次。
3.可以在每个构造器中赋值一次。
*/
public class FinalDemo04 {
private final String name = "黑马" ;
private final String name1;
private final String name2;
{
// 可以在实例代码块中赋值一次。
name1 = "黑马1";
}
public FinalDemo04(){
name2 = "黑马2";
}
public FinalDemo04(String a){
name2 = "黑马2";
}
public static void main(String[] args) {
FinalDemo04 f1 = new FinalDemo04();
System.out.println(f1.name);
//f1.name = "黑马1"; // 第二次赋值 报错!
}
}
面试常考(单例模式)
饿汉单例设计模式
/**
目标:面试常考(单例模式)。
单例模式的含义: 单例模式,是一种常用的软件设计模式。通过单例模式可以保证系统中,
应用该模式的这个类永远只有一个实例。即一个类永远只有一个对象实例。
单例是为了节约内存,单例在有些业务场景下还必须用到!!
单例的应用场景:在实际开发中,有很多业务对象永远只需要一个,无论启动多少次
我们只需要一个对象,例如任务管理对象,只需要一个对象。节约内存和性能。
因为对象越多内存占用越大,极有可能出现内存溢出!
实现单例模式目前提供两种方式:
1.饿汉单例设计模式
在用类获取对象的时候,对象已经提前为你创建好了。
设计步骤:
a.定义一个类,把构造器私有。
b.定义一个静态变量存储一个对象。
c.提供一个返回单例对象的方法。
2.懒汉单例设计模式
*/
public class SingleInstanceDemo01 {
public static void main(String[] args) {
Singleton01 s1 = Singleton01.getInstance();
Singleton01 s2 = Singleton01.getInstance();
System.out.println(s1 == s2);
}
}
// 饿汉单例设计模式
class Singleton01{
// b.定义一个静态变量存储一个对象( 在用类获取对象的时候,对象已经提前为你创建好了。)
private static final Singleton01 INSTANCE = new Singleton01();
// a.定义一个类,把构造器私有。
private Singleton01(){
}
// c.提供一个返回单例对象的方法。
public static Singleton01 getInstance(){
return INSTANCE;
}
}
懒汉单例设计模式
/**
目标:面试必考(单例模式)。
单例模式的含义: 单例模式,是一种常用的软件设计模式。通过单例模式可以保证系统中,
应用该模式的这个类永远只有一个实例。即一个类永远只有一个对象实例。
单例的应用场景:在实际开发中,有很多业务对象永远只需要一个,无论启动多少次
我们只需要一个对象,例如任务管理对象,只需要一个对象。节约内存和性能。
因为对象越多内存占用越大,极有可能出现内存溢出!
实现单例模式两种方式:
1.饿汉单例设计模式
在用类获取对象的时候,对象已经提前创建好了。
设计步骤:
a.定义一个类,把构造器私有。
b.定义一个静态变量存储一个对象。
c.提供一个返回单例对象的方法。
2.懒汉单例设计模式
在真正需要该对象的时候,才去创建一个对象(延迟加载对象)。
设计步骤:
a.定义一个类,把构造器私有。
b.定义一个静态变量存储一个对象。
c.提供一个返回单例对象的方法。
饿汉和懒汉的区别:
1、饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改
变。懒汉式如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的。
2、从实现方式来讲他们最大的区别就是懒汉式是延时加载,他是在需要的时候才创建对象,而饿汉
式在虚拟机启动的时候就会创建,饿汉式无需关注多线程问题,写法简单明了,能用则用。真正用
到的时候才去建这个单例对象,“饿汉式”是在不管用不用得上,一开始就建立这个单例对象。
*/
public class SingleInstanceDemo02 {
public static void main(String[] args) {
Singleton02 s1 = Singleton02.getInstance();
Singleton02 s2 = Singleton02.getInstance();
System.out.println(s1 == s2);
}
}
// 懒汉单例设计模式
class Singleton02{
// b.定义一个静态变量存储一个对象(这里不能创建对象,需要的时候才创建,这里只是一个变量用于存储对象!)
public static Singleton02 instance ;
// a.定义一个类,把构造器私有。
private Singleton02(){
}
// c.提供一个返回单例对象的方法。
public static Singleton02 getInstance(){
if(instance == null){
// 第一次来拿单例对象!需要创建一次对象,以后直接返回!!
instance = new Singleton02();
}
return instance;
}
}
枚举的应用
/**
目标:枚举的概述和作用。
枚举是Java中的一种特殊类型。
枚举的作用:是为了做信息的标志和信息的分类。
定义枚举的格式:
修饰符 enum 枚举名称{
第一行都是罗列枚举实例的名称。
}
枚举类的编译以后源代码:
public final class Season extends java.lang.Enum<Season> {
public static final Season SPRING = new Season();
public static final Season SUMMER = new Season();
public static final Season AUTUMN = new Season();
public static final Season WINTER = new Season();
public static Season[] values();
public static Season valueOf(java.lang.String);
}
枚举的特点:
1.枚举类是用final修饰的,枚举类不能被继承!
2.枚举类默认继承了java.lang.Enum枚举类。
3.枚举类的第一行都是常量,存储都是枚举类的对象。
4.枚举类的第一行必须是罗列枚举类的实例名称。
所以:枚举类相当于是多例设计模式。
小结:
枚举类的特点:
1.枚举类是用final修饰的,枚举类不能被继承!
2.枚举类默认继承了java.lang.Enum枚举类。
3.枚举类的第一行都是常量,存储都是枚举类的对象。
4.枚举类的第一行必须是罗列枚举类的实例名称。
所以:枚举类相当于是多例设计模式。
*/
public class EnumDemo {
}
enum Sex{
BOY , GIRL;
}
// 枚举
enum Season {
SPRING , SUMMER , AUTUMN , WINTER;
}
/**
目标:枚举的作用:是为了做信息的标志和信息的分类。
常量做信息分类和信息标志:
虽然可以实现可读性,但是入参不受限制!!!
Java建议做信息标志和信息分类应该使用枚举实现:最优雅的方式。
可以实现可读性,而且入参受限制,不能乱输入!!!
小结:
枚举的作用:是为了做信息的标志和信息的分类。
*/
enum Oritation{
UP , DOWN , LEFT , RIGHT ;
}
public class EnumDemo02 {
public static void main(String[] args) {
move(Oritation.RIGHT); // 方法入参只能输入枚举的4个类型!
}
// 提供一个方法控制玛丽的方向。
// 上下左右
public static void move(Oritation o){
switch (o){
case UP:
System.out.println("让🐎往👆蹦~~~~");
break;
case DOWN:
System.out.println("让🐎往👇蹦~~~~");
break;
case LEFT:
System.out.println("让🐎往👈蹦~~~~");
break;
case RIGHT:
System.out.println("让🐎往👉蹦~~~~");
break;
}
}
// public static final int UP = 0;
// public static final int DOWN = 1;
// public static final int LEFT = 2;
// public static final int RIGHT = 3;
// public static void main(String[] args) {
// move(RIGHT);
// }
//
// // 提供一个方法控制玛丽的方向。
// // 上下左右 0 1 2 3
// public static void move(int oritatin){
// switch (oritatin){
// case 0:
// System.out.println("让🐎往👆蹦~~~~");
// break;
// case 1:
// System.out.println("让🐎往👇蹦~~~~");
// break;
// case 2:
// System.out.println("让🐎往👈蹦~~~~");
// break;
// case 3:
// System.out.println("让🐎往👉蹦~~~~");
// break;
// default:
// System.out.println("蒙蔽了~~~~");
// }
// }
}
/**
拓展:枚举的API
*/
public class EnumDemo03 {
public static void main(String[] args) {
Season03 s = Season03.SPRING;
System.out.println(s); // SPRING
System.out.println("---------------");
// 获取当前类的全部枚举实例 : public static Season[] values()
Season03[] ss = Season03.values();
for(int i = 0 ; i < ss.length ; i++ ){
Season03 s1 = ss[i];
System.out.println(s1);
}
// 获取枚举对象的索引: ordinal()
Season03 s2 = Season03.AUTUMN;
System.out.println(s2.ordinal()); // 2
}
}
enum Season03{
SPRING, SUMMER , AUTUMN, WINTER ;
}
enum Sex03{
BOY , GIRL;
}