2019-7-4 [JavaSE] 程序包 访问修饰符 static修饰符与static块运行原理 [项目案例:图书管理系统2.0]

1.构造方法调用

在这里插入图片描述
调用本类构造,必须用this语句;
位置:必须写在 构造器中;
必须是构造的第一行代码处。

class WebUser{
	private int userId;
	private String userPwd = "999999";
	private String userPwd;
	private String userEmail;	
//	构造块
	{
		this.userPwd = "999999";
	}
	public WebUser() {
		this.userPwd = "999999";
	}	
	public WebUser(int userId, String userEmail) {
		//调用带参数的构造
		this(userId,"999999",userEmail);
		/*
		 * 调用本类构造,必须用this语句;
		 * 位置:必须写在 构造器中;
		 *      必须时构造的第一行代码处。
		 */
		this();//调用本类构造器
		this.userId = userId;
		this.userEmail = userEmail;
		this.userPwd = "999999";		
	}
	public WebUser(int userId, String userPwd, String userEmail) {
		this.userId = userId;
		this.userPwd = userPwd;
		this.userEmail = userEmail;
	}
		
	public int getUserId() {
		return userId;
	}
	public WebUser setUserId(int userId) {
		this.userId = userId;
		return this;
	}
	public String getUserPwd() {
		return userPwd;
	}
	public WebUser setUserPwd(String userPwd) {
		this.userPwd = userPwd;
		return this;
	}
	public String getUserEmail() {
		return userEmail;
	}
	public WebUser setUserEmail(String userEmail) {
		this.userEmail = userEmail;
		return this;
	}
	public String show() {
		return userId + "\t" + userPwd + " \t" + userEmail;
	}		
}
public class TestWebUser {

	public static void main(String[] args) {
		//              链式调用setter访问器               
		WebUser user = new WebUser().setUserEmail("user@qq.com").setUserPwd("123456").setUserId(222);
		
		user.setUserId(11);
		user.setUserEmail("aa@qq.com");
		System.out.println(user.show());
		WebUser user1 = new WebUser().setUserId(111);
		
		System.out.println(user1.show());
		WebUser user1 = new WebUser();
		
		System.out.println(user1.show());
		WebUser user2 = new WebUser(11, "user2@163.com");
		
		System.out.println(user2.show());//11	999999 	user2@163.com
		WebUser user3 = new WebUser(22, "123456", "user3@163.com");
		
		System.out.println(user3.show());
	}
}

2.包解决的问题

在这里插入图片描述
程序包:用来管理类和接口的工具,是类和接口的集合

2.1 创建

定义程序 包:
package 包名;
package 父包名.子包名[.……];
注意:
1.通常包名都用小写字母;
2.位置必须在java文件的第一行代码处;
3.只能有一行 package语句;
4.同一个项目下包名不能重复。
通常:域名反转.部门名.项目名;

2.2使用

同一个包下,直接使用;
不同的包下:
1)导入程序包下的类型;
import 包名.类型名;
2)完全限定名称
在这里插入图片描述
优点:
1.方便查找;
2.避免命名冲突;
3.更好的提供了封装

3.访问修饰符

在这里插入图片描述

4.static修饰符

静态:修饰 类,成员变量,成员方法,代码块

4.1 修饰变量

在这里插入图片描述
在这里插入图片描述

class Student{
	int count = 0;
}
public class TestStudent {

	public static void main(String[] args) {
		Student guojing = new Student();
		guojing.count ++;
		Student huangrong = new Student();
		huangrong.count ++;
		
		System.out.println(guojing.count);//1
		System.out.println(huangrong.count);//1
	}
}

在这里插入图片描述
静态变量(类变量)
//类加载的时候 初始化
//静态变量 属于类,不属于对象
//被所有对象所共享
//优先于 对象而存在

class Student{
	//静态变量(类变量)
	//类加载的时候 初始化
	//静态变量 属于类,不属于对象
	//被所有对象所共享
	//优先于 对象而存在
	static int count = 0;
}
public class TestStudent {

	public static void main(String[] args) {
		//类名.静态变量名(可以不创建对象)
		Student.count ++;
		Student.count ++;
		System.out.println(Student.count);
    }
}

总结静态变量:
1.名称:静态变量(类变量);
2.属于类,不属于对象;
3.在类加载时,初始化;
4.优先于对象而存在的;
5.被所有对象所共享。
使用语法:
类名.静态变量名; //使用
对象名.静态变量名;
场合: 共享空间。
在这里插入图片描述

4.2 修饰方法

静态方法(类方法):
场合: 1.类不能创建对象 ,想实现功能,调用静态方法实现;
2.简单。
在这里插入图片描述

public class TestStaticMethod1 {
	int n = 11;
	static int sn = 22;
	//实例成员方法
	public void f() {
		System.out.println("f");
		System.out.println(n);
		System.out.println(sn);//使用静态成员
	}
	//静态方法(类方法)
	public static void sf() {
		System.out.println("sf");
		//静态方法中只能直接访问静态成员
		System.out.println(sn);
		//非静态的创建对象
		System.out.println(new TestStaticMethod1().n);
		//不能使用this,super	
	}
	public static void main(String[] args) {
		TestStaticMethod1.sf();//使用
		new TestStaticMethod1().sf();//
		new TestStaticMethod1().f();
	}
}

4.3 修饰代码块

在这里插入图片描述
代码块:
1) 构造块
class 类{
{
//构造块:初始化对象的。
}
}
2)静态块
static {
//静态块:初始化类
}

class Demo{
	static{
		System.out.println("Demo的静态块");
	}
	{
		System.out.println("构造块");
	}
	Demo(){
		System.out.println("构造器");
	}
}
public class TestStaticMethod2 {//启动类,主类
/*	static {
		System.out.println("静态块");
	}*/
	public static void main(String[] args) {
		Demo demo = new Demo();//引起了类的加载
		Demo demo1 = new Demo();//类不会重复加载
	//	ClassLoader.getSystemClassLoader().loadClass(name)//了解以下原码
//可以知道为什么请看最后一个
	}
}

3)局部代码块
public void 方法名(){
{
//局部块:
//限制 局部变量的使用范围和生命周期。
}
}

public void f() {
		int n = 11;
		System.out.println(n);
		//局部块
		{
			int m = 22;
			System.out.println(m);
		}
	}

4.4 静态变量初始化

在这里插入图片描述

class Demo1{
	static int sn = 11;
	static {
		sn = 22;
	}
}
public class TestStaticMethod3 {

	public static void main(String[] args) {
		System.out.println(Demo1.sn);//22
	}
}

4.5 静态导入

格式:
import  static 包名.类名.静态变量名(方法);

在这里插入图片描述

4.6 单例模式

只能创建一个对象。
/饿汉式特点:
1.这个对象类加载时就加载了,就有了;
2.线程安全的。

class Window{
	 //静态变量只初始化一次
	 private static Window win = new Window();
	 static {
		 System.out.println("static");
	 }
	 private Window(){}
	 public static  Window getWindow() {
		 return win;
	 }
}

//懒汉式 特点:
1 .在使用的时候 创建对象;
2.线程非安全的。

class Window{
	 //静态变量只初始化一次
	 private static Window win = null;
	 private Window(){}
	 public static  Window getWindow() {
		 if(win == null) {
			 win = new Window();
		 }
		 return win;
	 }
}

5.编写:静态修饰符 3个人从篮子里拿苹果

class Child{
	private String name;
	// 共享的6个苹果
	private static int appleCount = 6;
	public Child(String name) {
		this.name = name;
	}
	// getter
	public int getAppleCount() {
		return appleCount;
	}
	// 拿苹果
	public  void getApple() {
		appleCount --;
		System.out.println(name + "拿了一个苹果");	
	}
}
public class TestChild_exam {
	public static void main(String[] args) {
		Child guojing = new Child("郭靖");
		Child yangkang = new Child("杨康");
		Child huangrong = new Child("黄蓉");
		guojing.getApple();
		yangkang.getApple();
		huangrong.getApple();
		System.out.println("剩下" + guojing.getAppleCount());
	}
}

6.项目案例:图书管理系统2.0

需求:使用类和方法对于图书管理系统进行升级
在这里插入图片描述
代码如下:

import java.util.Scanner;

class Book{
	private int no;
	private String name;
	private double price;
	public Book() {
	}
	public Book(int no, String name, double price) {
		this.no = no;
		this.name = name;
		this.price = price;
	}
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	public String show() {
		return no + "\t" + name + "\t" + price;
	}	
}

class ManagerBook{
	private Book [] books = new Book[100];// null,null,null……………………
	public void add(Book book) {
		for(int i = 0; i < books.length; i++) {
			if( books[i] == null) {
				books[i] = book;
				System.out.println("添加成功");
				break;
			}
		}
	}
	public void update(int no , double price) {
		for(int i = 0; i < books.length; i++) {
			if(books[i].getNo() == no) {
				books[i].setPrice(price);
				System.out.println("修改成功");
				break;
			}
		}
	}
	public void delete(int no) {
		for(int i = 0; i < books.length; i++) {
			if(books[i].getNo() == no) {
				//覆盖
				for(int j = i; j < books.length -1; j ++) {
					books[j] = books[j + 1];
				}
				if(books[books.length -1] != null) {
					books[books.length -1] = null;
				}
				System.out.println("删除成功");
				break;
			}
		}
	}
	public void queryAll() {
		System.out.println("图书编号\t图书名称\t图书价格");
		for(Book book : books) {
			if(book == null) {
				break;
			}
			System.out.println(book.show());
		}
	}
}

public class TestBook {

	public void startMenu() {
		Scanner input = new Scanner(System.in);
		ManagerBook mgr = new ManagerBook();
		System.out.println("\t-菜单-");
		System.out.println("\t 1.添加;2.修改;3.删除;4.查询;5.退出\n");
		int menuNo;
		int no;
		String name;
		double price;
		while(true) {
			System.out.println("-- 输入菜单项:");
			menuNo = input.nextInt();
			switch(menuNo) {
			case 1:
				//add
				System.out.println("--输入编号:");
				no = input.nextInt();
				System.out.println("--输入名称:");
				name = input.next();
				System.out.println("--输入价格:");
				price = input.nextDouble();
				
				Book book = new Book(no, name, price);
//	或者:
//          	book.setName(name);
//				book.setNo(no);
//				book.setPrice(price);
				
				mgr.add(book);
				break;
			case 2:
				//update
				System.out.println("--输入要修改的图书编号:");
				no = input.nextInt();
				System.out.println("--输入新的价格:");
				price = input.nextDouble();
				mgr.update(no, price);
				break;
			case 3:
				//delete
				System.out.println("--输入要删除的图书编号:");
				no = input.nextInt();
				mgr.delete(no);
				break;
			case 4:
				//select 
				mgr.queryAll();
				break;
			case 5:
				System.out.println("退出应用程序");
				System.exit(0);
			}
		}
	}
	public static void main(String[] args) {
//		TestBook test = new TestBook();
//		test.startMenu();
		//匿名对象 :只能使用一次
		new TestBook().startMenu();
	}
}

7.为什么static块只被执行一次?

那么static块到底在什么时候运行的呢?如果了解JVM原理,我们知道,一个类的运行分为以下步骤:

1.装载
2.连接
3.初始化

其中装载阶段又三个基本动作组成
1.通过类型的完全限定名,产生一个代表该类型的二进制数据流
2.解析这个二进制数据流为方法区内的内部数据结
3.构创建一个表示该类型的java.lang.Class类的实例
另外如果一个类装载器在预先装载的时遇到缺失或错误的class文件,它需要等到程序首次主动使用该类时才报告错误。

连接阶段又分为三部分:
1.验证,确认类型符合Java语言的语义,检查各个类之间的二进制兼容性(比如final的类不用拥有子类等),另外还需要进行符号引用的验证。
2.准备,Java虚拟机为类变量分配内存,设置默认初始值。
3.解析(可选的) ,在类型的常量池中寻找类,接口,字段和方法的符号引用,把这些符号引用替换成直接引用的过程。

当一个类被主动使用时,Java虚拟就会对其初始化,如下六种情况为主动使用:
1.当创建某个类的新实例时(如通过new或者反射,克隆,反序列化等)
2.当调用某个类的静态方法时
3.当使用某个类或接口的静态字段时
4。当调用Java API中的某些反射方法时,比如类Class中的方法,或者java.lang.reflect中的类的方法时
5.当初始化某个子类时
6.当虚拟机启动某个被标明为启动类的类(即包含main方法的那个类)
Java编译器会收集所有的类变量初始化语句和类型的静态初始化器,将这些放到一个特殊的方法中:clinit。
 
实际上,static块的执行发生在“初始化”的阶段。初始化阶段,jvm主要完成对静态变量的初始化,静态块执行等工作,正因为初始化只会进行一次,所以static只会执行一次。

下面我们看看执行static块的几种情况:

1、第一次new A()的过程会打印"";因为这个过程包括了初始化

2、第一次Class.forName(“A”)的过程会打印"";因为这个过程相当于Class.forName(“A”,true,this.getClass().getClassLoader());

3、第一次Class.forName(“A”,false,this.getClass().getClassLoader())的过程则不会打印""。因为false指明了装载类的过程中,不进行初始化。不初始化则不会执行static块。

8.注意

1.代码只能有一个public 名称与文件名一致;通常是主函数
2.即使不用也叫加一个无参的构造器,保证可以创建一个最基本的对象
3.编程思路:没有模板创建模板
4.匿名对象只能使用一次,再用再写
5.return this;this可以用来返回调用的数据结果
6.当以后对象比较多时,可以用这个方法直接在new里赋值,在get里return this即可。
7.import导入可以导入很多个
import a.A导入a包里的A
import a.是导入a包所有的类型
8.完全限定名称:
a.A a =new a.A()
这个方式用的不多
9.import b.c.C/import b.

调用小包需要写全,否则不调用
10.如果两个包下有同名的类,就要用完全限定名称的方式。
11.public的访问权限是最高的
12.访问修饰符一共就只有4个
13.static修饰符是静态的,可以用来修饰类,类中的成员变量,代码块,成员方法
14.变量加static就会变成公共的了
由此编程静态变量,

存储方式改变:
	1.内存里开辟出一个方法区
	2.其中有一个静态区,专门存储静态变量
	3.对于静态变量的初始化,系统在类加载的时候完成
	4.类加载的时候会初始化,而静态变量属于类,不属于对象,静态变量被所有对象所共享。

15.字节码文件(.class)被放在内存里释放,由JVM虚拟机进行解码加载,此过程如下解释:

	1.虚拟机把class文件加载到方法区里,加载成功后会生成一个对应的对象在堆中,
	这个对象还是.class,不过是在堆里,这样就可以被new了。
	2.看看类中有没有静态变量,有则为其开辟空间在静态区里,默认初始化为03.随后进行声明处初始化,至此这个类就可以被正常使用了。

16.类名.静态变量名 :可以不创建对象,直接使用,被所有对象所共享。
17.静态变量优先于对象而存在
18.静态块在第一次主动加载类时,也就是无需调用,写上就能用,例如写在主类之中。
包含主方法的类叫做启动类/主类
19.类是不会重复加载的
20.局部代码块的主要目的:

	1.限制代码块里的代码适用范围和生命周期。
	2.当代码块被执行完,代码块里的变量就会被释放掉。

21.饿汉式:

	1无论是否想用,只要类一加载就会被执行,例如反射时触发它执行。
	2.多线程安全的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值