六、第六章——面向对象封装、继承、多态等基础知识

day09-课堂笔记

1、关于Java的集成开发环境 【集成开发环境简称:IDE】

1.1 什么是集成开发环境?

* 集成开发环境讲究一站式开发,使用这个工具即可。有提示功能,有自动纠错功能。

* 集成开发环境可以让软件开发变的更简单、更高效。

* 没有IDE工具:
- 需要安装JDK、需要配置环境变量、需要手动的将java源文件编译生成class字节码文件
- java源程序出错之后还没有提示
- 没有自动提示功能等。

* 有IDE工具:
- 不需要独立安装地JDK 【IDE中已经集成】
- 不需要手动配置环境变量
- 不需要使用javac命令对它java源文件进行编译
- 并且java源程序编写语法错误马上有提示
- 使用IDE工具有很多代码不需要写,自动生成的。

1.2 java有哪些比较牛的IDE呢?

* eclipse (myeclipse) 【最多】
* Intellij IDEA 【上升的趋势】
* NetBeans
* JBuilder

目前阶段我们使用的是:myeclipse10

 

2 讲解myeclipse的使用

* workspace: 工作区
- 当myeclipse打开的时候,大多数都是会选择工作区
- 这个工作区可以是已存在的工作区,也可以是新建的工作区
- 选择工作区之后,将来编写的java代码,自动编译的class文件都可以在工作区中找到
- myeclipse可以开启两个甚至更多的会话,每一个会话对应不同的workspace

* 在workspace工作区当中有一个文件夹:.metadata
- 在该文件夹当中存储了当前myeclipse的工作状态
- 将.metadata文件夹删除之后,下一次再次进入这个工作区的时候,是一个全新的开始。但是会发现这个IDE工具当中所有的项目丢失了,没关系,这里只是丢失的myeclipse的项目,硬盘上真实存储的项目不会丢失。

* 打开myeclipse之后:
- 窗口可以拖动
- 可以放大缩小

* myeclipse为程序员准备了很多不同的布局方式:
- 企业级开发: JavaEE开发的专用布局- MyEclipse Java Enterprise
- 普通java开发的:JavaSE开发的专用布局 -java
- 怎么切换布局?
* myeclipse右上角

* 还原窗口布局
Window --> Reset Perspective

* 重点的窗口介绍
* Package explore / Navigator /Project Explore: 可以看到java源文件
* Console: 控制台窗口

* 工作区workspace中基本的单元是:Project (工程/项目)

* 使用myeclipse:
- 在Package Explore窗口当中点击右键 --> new --> Java Project 【JavaSE工程】
* 指定java工程的名称:一般全部小写
* 指定java工程的存放目录
* Java的运行时环境:JRE的配置 【可以选择使用myeclipse自带的JRE,也可以选择程序员自己安装的JRE】
* Project layout: 工程的目录布局
- 多数情况下都是选择:两个独立的文件夹存储源码(src)和字节码(bin)
           
* 在src目录下新建软件包:package机制后面讲,目前先用着。
- 在src目录上点击右键 --> new --> package
   - 给package起名:com.bjpowernode.javase;
- 包package是java中语法的一部分。后面讲

* 在软件包下新建一个java类:
- 在包上点击鼠标右键 --> new --> class 【还可以同时生成了main方法】    
   - 显示行号
  在java源程序的左侧栏上点击右键 --> Show Line Numbers
   -  设置字体大小
  window --> Preferences --> 输入font --> colors and fonts -- Basic --> Text Font --> Edit
 
* 关于myeclipse中常用的部分快捷键:
- ctrl + d  删除当前行
- alt + /  自动补全
- ctrl + alt + down  复制当前行
- shift + enter  在当前行换行

* 注意:myeclipse当中的java源代码有的时候不保存是不会编译的。所以时刻记住:ctrl + s

* myeclipse当中,出现红色下划线的表示编译错误,语法错误。鼠标停留在红色的下划线上面会有错误提示信息。并且点击左边的叉号,可以进行纠错。 【当然也可以光标停留在红色下划线上面:ctrl + 1

* 有的时候程序出现黄色的下划线,格非警告,编译可以通过。

* 快捷键怎么设置?
window --> Preferences --> keys

* 怎么运行一个带有主方法的java程序?
* 在java源程序的任何位置点击鼠标右键 --> Run As --> Java Application

 

3 面向对象的封装性

3.1 封装的引入

* 用户测试类
* 对于当前程序来说:User类中的age属性在外部程序中可以随意访问,导致age属性不安全,一个User对象表示一个用户,用户的年龄不可能为负数,以下程序当中年龄值为负数,程序运行的时候并没有报错,这是当前程序存在的缺陷。

* 面向对象包括三大特征:
- 封装
- 继承
   - 多态
 
* 当前主要讲解的是封装机制。为什么要封装?封装有什么好处?
- 封装之后,对于那个事物来说,看不到这个事物比较复杂的那一面,只能看到该事物简单的一面。复杂性封装,对外提供简单的操作入口。照相机就是一个很好的封装的案例,照相机实现原理相当复杂,但是双十一地使用照相机的人来说,操作起来是非常方便的
- 封装之后才会形成真正的“对象”,真正的“独立体”。
   - 封装就意味着以后的程序可以重复使用。并且这个事物应该适应性较强,在任何场合都可以使用。
   - 封装之后,对于事物本身,提高了安全性。 【安全级别高】


public class UserTest {
public static void main(String[] args) {

// 创建User对象
User user = new User();

// 访问age
// 读取年龄值 【get】
System.out.println("该用户年龄: " + user.age);

// 修改年龄值 【set】
// myeclipse快捷键:ctrl + shift + F
user.age = 18;
System.out.println("该用户年龄: " + user.age);

// 修改年龄值
// 这里的age属性显然是完全暴露给外部程序的,对于程序员来说可以操作User对象中所有的细节,导致User中部分数据不安全。
// 不建议这样,建议User对类型进行封装地,建议在外部程序中不能随意访问User对象当中的属性,这样可以保证属性的安全。
user.age = -100;
System.out.println("该用户年龄: " + user.age);
}
}

 

3.2 封装的步骤和作用

封装的步骤:
1、所有属性私有化,使用private关键字进行修饰,private表示私有的,修饰的所有数据只能在本类中访问。
2、对外提供简单的操作入口,也就是说以后外部程序想访问age属性,必须通过这些简单的入口进行访问:
- 对外提供两个公开的方法,分别是set方法和get方法
- 想修改age属性,调用set方法
- 想读取age属性,调用get方法
3、set方法的命名规范:
public void set+属性名首字母大写(形参){
}
public void setAge(int a){
age = a;
}

4、get方法的命名规范:
public void getAge(){
return age;
      }

回想一下,一个属性访问的时候包括几种访问形式?
- 第一种方式:想读取这个属性的值,读取get
- 第二种方式:想修改这个属性的值,修改set

需要大家先背会以上内容:
- setter and getter方法没有static关键字
   - 有static关键字修饰的方法怎么调用:类名.方法名(实参);
   - 没历static关键字修饰的方法怎么调用:引用.方法名(实参);

User.java

public class User {
//属性私有化
private int age;

//set方法没有返回值,因为set方法只负责修改数据
/*
public void setAge(int age){
age = age; //java就近原则,这里其实并没有给age属性赋值,这里的age都是局部变量age
}
*/

//setter
public void setAge(int a){
//编写业务逻辑代码进行安全控制
//age = a;

if(a < 0 || a > 150){
System.out.println("对不起,您提供的年龄不合法");
return;
}

//程序可以执行到这里,说明a年龄是合法的,则进行赋值运算
age = a;
}

//getter
public int getAge(){
return age;
}
}

UserTest.java

public class UserTest {

public static void main(String[] args) {

//创建User对象
User user = new User();

//编译报错,age属性私有化,在外部程序当中不能直接访问
//从此之后age属性非常安全,但是有点太安全了。
//对于目前的程序来说,age属性彻底在外部访问不到了。
// System.out.println(user.age);

//修改
user.setAge(-100);

//读取
System.out.println(user.getAge());
}
}

 

3.3 封装的应用

Customer.java

public class Customer {

//属性
private int id;
private String name;
private int age;
private String addr;

public 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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
}

CustomerTest.java

public class CustomerTest {

	public static void main(String[] args) {
		
		Customer c = new Customer();
		
		//私有的属性不能直接在外部访问
		//c.id = 410;
		
		//操作入口变成了只能通过set和get方法进行访问
		//在set方法和get方法执行过程中可以进行安全过滤
		c.setId(100);
		c.setName("xiaohong");
		c.setAge(50);
		c.setAddr("楚雄");
		
		System.out.println(c.getId());
		System.out.println(c.getName());
		System.out.println(c.getAge());
		System.out.println(c.getAddr());
	}
}

 

4 构造方法

4.1 构造的语法结构和基本使用

1、构造方法又被称为构造函数/构造器/Constructor

2、构造方法语法结构:
	[修饰符列表] 构造方法名(形式参数列表){
		构造方法体;
	}
3、回顾普通方法的语法结构:
	[修饰符列表] 返回值类型 方法名(形式参数列表){
		方法体;
	}
	
4、对于构造方法来说,“返回值类型”不需要指定,并且也不能写void,只要写上void,那么这个方法就成为普通方法了。

5、对于构造方法来说,构造方法的方法名必须和类名保持一致。

6、构造方法的作用?
	构造方法存在的意义是,通过构造方法的调用,可以创建对象。

7、构造方法应该怎么调用?
	- 普通方法是这样调用的:类名.方法名(实参列表) 或者 引用.方法名(实参列表)
	- new 构造方法名(实参列表)
	
8、构造方法调用执行之后一,有返回值吗?
	- 每一个构造方法实际上执行结束之后都有返回值,但是这个“return 值;”这样的语句不需要我们写。
	- 并且返回值类型是构造方法所在类的类型。由于构造方法的返回值类型就是类本身,所以返回值类型不需要编写
	
9、注释和取消注释:ctrl + /, 多行注释:ctrl + shift + /	

10、当一个类中没有定义任何构造方法的话,系统默认给该类提供一个无参数的构造方法,这个构造方法被称为缺省构造器

11、当一个显示的将构造方法定义出来了,那么系统则不在默认为这个类提供缺省构造器。建议开发中手动的为当前类提供无参数构造方法。因为无参数构造方法太常用了。

12、构造方法支持重载机制。在一个类当中编写多个构造方法,这多个构造方法显然已经构成方法重载机制。

User.java

public class User {
	
	//无参数构造方法
	public User(){
		System.out.println("User's default Constructor Invoke!");
	}
	
	//有参数的构造方法
	public User(int i){
		System.out.println("带有int类型的构造器");
	}
	
	//有参数构造方法
	public User(String name){
		System.out.println("带有String类型的构造器");
	}
	
	//有参数构造方法
	public User(int i, String name){
		System.out.println("带有int,String类型的构造器");
	}
}

ConstructorTest01.java

public class ConstructorTest01 {

	public static void main(String[] args) {

		//创建User对象
		//调用User类的构造方法来完成对象的创建
		//以下程序创建了4个对象,只要构造函数调用就会创建对象,并且一定是“堆内存”中开辟内存空间。
		User u1 = new User();
		User u2 = new User(10);
		User u3 = new User("xiaohong");
		User u4 = new User(11, "xiaohong");
				
		//调用带有static的方法:类名.
		ConstructorTest01.doSome();
		doSome();
		
		//调用没有static的方法:引用.
		//doOther方法在ConstructorTest01类当中,所以需要创建ConstructorTest01对象
		//创建constructortest01对象,调用无参构造方法。		 
		ConstructorTest01 t = new ConstructorTest01();  //类中没有任何构造方法的话,系统默念提供一个无参构造器
		t.doOther();
	}
	
	public static void doSome(){
		System.out.println("do some!");
	}
	
	public void doOther(){
		System.out.println("do other");
	}
	
}

 

4.2 构造方法的其它作用

构造方法的作用:
	1、创建对象
	2、创建对象的同时,初始化实例变量的内存空间。 【给实例变量赋值】
	
成员变量之实例变量,属于对象级别的变量,变种变量必须先对象才能有实例变量。
实例变量没有手动赋值的时候,系统默认赋值,那么这个系统默认赋值是在什么时候完成的呢?
	是在类加载的时候吗?
		不是,因为类加载的时候只加载了代码片段,还没来得及创建对象。所以此时实例变量并没有初始化。
	实际上,实例变量的内存空间是在构造方法执行过程当中完成开辟的。完成初始化的。
	系统在默认赋值的时候,也是在构造方法执行过程当中完成赋值的
	
实例变量默认值:
	byte,short,int,long  0
	float,double  0.0
	boolean  false
	引用数据类型   null

Account.java

//账户类
public class Account {
	
	//账号
	private String actno;  //实例变量/对象变量,也就是详,必须先对象才能有对应的实例变量
	
	//余额
	private double balance;
	
	//无参构造器
	public Account(){
		//初始化实例变量的内存空间
		//actno = null;
		//balance = 0.0;
	}
	
	public Account(String s){
		actno = s;
	}
	
	public Account(double d){
		balance = d;
	}
	
	public Account(String s, double d){
		balance = d;
		actno = s;
	}
	
	public String getActno() {
		return actno;
	}

	public void setActno(String actno) {
		this.actno = actno;
	}

	public double getBalance() {
		return balance;
	}

	public void setBalance(double balance) {
		this.balance = balance;
	}
}

ConstructorTest02.java

public class ConstructorTest02 {

	public static void main(String[] args) {

		//查看访问的是哪个属性,查看访问是哪个方法?
		//按ctrl键,鼠标移动到查看的元素上,出现下划线的时候开始单击
		//另外,在一个类中,想快速查看:strl + o,输入要查看的内容
		//创建对象
		Account act1 = new Account();
		System.out.println("账号:" + act1.getActno());
		System.out.println("余额:" + act1.getBalance());
		
		Account act2 = new Account("120");
		System.out.println("账号:" + act2.getActno());
		System.out.println("余额:" + act2.getBalance());

		Account act3 = new Account(1000000);
		System.out.println("账号:" + act3.getActno());
		System.out.println("余额:" + act3.getBalance());
		
		Account act4 = new Account("xiaohong", 10000000);
		System.out.println("账号:" + act4.getActno());
		System.out.println("余额:" + act4.getBalance());	
        
	}
}

 

5 对象和引用

5.1 对象和引用的概念

* 对象:目前在使用new运算符在堆内存中开辟的内存空间称为对象。

* 引用:是一个变量,不一定是局部变量,还可能是成员变量。引用保存了内存地址,指向了堆内存当中的对象。

* 所有访问实例相关的数据,都需要通过“引用.”的方式访问,因为只有通过引用才能找到对象。

* 只有一个空的引用,访问对象的实例相关的数据会出现空指针异常。	

 

5.2 参数的传递

主要研究和学习的是方法在调用的时候,涉及到参数传递的问题,到底是怎么传递数据的呢?

值传递
int i = 10;
int j = i;  //i传递给是j,实际上只是将i变更中保存的10传递给j了,j实际上是一块全新的内存空间。

User u = 0x1234;
User u2 = u;  //u传递给u2,实际上是将0x1234这个值赋值给u2了,u和u2实际上是两个不同的局部变量,但是它们这两个变量指向堆内存中同一个java对象

 

/*
	java语言当中方法调用的时候涉及到参数传递的问题,参数传递实际上传递的是变量中保存的具体值
	int i = 10;
	add(i)  //add(10)
*/

public class Test01 {

	public static void main(String[] args) {
		
		int i = 10;
		add(i);  //add方法调用的时候经,给add方法传递了一个变量i,到底传的是什么?
		System.out.println("main --> " + i);  //10
	}
	
	public static void add(int i){
		i++;
		System.out.println("add --> " + i);  //11
	}
}

 

 

 

package com.bjpowernode.javase.day09.test006;

/*
	最终结论:
		方法调用的时候,涉及到参数传递的问题,传递的时候,java只遵循一种语法机制,就量将变量中保存的“值”传递过去了,只不过有的时候变个值是一个字面值,有的时候这个值是另一个java对象的内存地址
*/

public class Test02 {

	public static void main(String[] args) {
		User u = new User(18);
		
		//传递u给add方法的时候,实际上传递的是u变量中保存的值,只不过这个值是一个java对象的内存地址。
		add(u);
		System.out.println("main --> " + u.age);  //19
	}
	public static void add(User u){
		u.age++;
		System.out.println("add --> " + u.age);  //19
	}

}

class User{
	
	//实例变量
	int age;
	
	//构造方法
	public User(int i){
		age = i;
	}
}

 

 

6 this关键字

6.1 this关键字引入

1、this是一个关键字,翻译为:这个

2、this是一个引用,this是一个变量,this变量中保存的内存地址指向了自身,this存储在JVM堆内存java对象内部

3、创建100个java对象,每一个对象都有this,也就说有100个不同的this

4、this可以出现在“实例方法”当中,指向当前正在执行这个动作的对象。 【this代表当前对象】

5、this在多数情况下是可以省略不写的

6、this不能使用在带有static的方法当中

Customer.java

public class Customer {

//姓名
String name;

//构造方法
public Customer(){

}

//不带有static关键字的一个方法
//顾客购物的行为
//每一个顾客购物最终的结果是不一样的
//所以购物这个行为是属于对象级别的行为
//由于每一个对象在执行购物这个动作的时候最终结果不同,所以购物这个动作必须有“对象”参与。
//重点:没有static关键字的方法被称为“实例方法”,实例方法怎么访问?“引用.”
//重点:没有static关键字的变量被称为“实例变量”
//注意:当一个行为/动作执行的过程当中需要对象参与的,那么这个方法一定要定义为“实例方法”,不要带有static关键字
//以下方法定义为实例方法,因为每一个顾客在真正购物的时候,最终的结果是不同的。所以这个动作在完成的时候必须有对象的参与。
public void shopping(){
//当张三在购物的时候,输出:张三在购物
//当李四在购物的时候,输出:李四在购物

//由于name是一个实例变量,所以这个name访问的时候一定访问的是当前对象的name
//所以多数情况下“this.”是可以省略的
System.out.println(name + "在购物!");

//完整写法
System.out.println(this.name + "在购物");
}

//带有static
public static void doSome(){
//这个执行过程中没有“当前对象”,因为带有static的方法是通过类名的方式访问的
//或者说这个“上下文”当中没有“当前对象”,自然也不存在this(this代表的是当前正在执行这个动作的对象)

//以下程序为什么编译错误呢?
//doSome方法调用不是对象去调用,是类名去调用,执行过程中没有“当前对象”
//name是一个“实例变量”,以下代码的含义是:访问当前对象的name,没有当前对象,自然也不能访问当前对象的name
//static的方法调用不需要对象,直接使用类名,所以执行过程中没有当前对象,所以不能使用this
//System.out.println(name);
}

public static void doOther(){
//假设想访问name这个变量的话应该怎么做?

//可以采用以下方案,但是以下方案,绝对不是访问的当前对象的name
//创建对象
Customer c = new Customer();
System.out.println(c.name);  //这里访问的name是c引用指向对象的name
}

}

CustomerTest.java

public class CustomerTest {

public static void main(String[] args) {

//创建Customer对象
Customer c1 = new Customer();
c1.name = "zhangsan";
c1.shopping();

//再创建Customer对象
Customer c2 = new Customer();
c2.name = "lisi";
c2.shopping();

//调用doSome方法(修饰符列表上有static)
//采用“类名.”的方式访问,显然这个方法在执行的时候不需要对象的参加
Customer.doSome();
}

}

 

6.2 this关键字使用1

最终结论:
在带有static的方法当中不能“直接”访问实例变量和实例方法。
因为实例变量和实例方法都需要对象的存在。
而static的方法当中是没有this的。也就是说当前对象是不存在的。
自然是无法访问当前对象的实例变量和实例方法。
public class ThisTest {

//实例变量(“引用.”的方法访问)
int num = 10;

//带有static的方法
//JVM负责调用main方法,JVM是怎么调用的?
//ThisTest.main(String[]);
public static void main(String[] arsg){

//以下代码什么意思?
//访问当前对象的num属性
//System.out.println(num); //编译错误
//System.out.printsln(this.num) //编译错误

//想访问num怎么办?
ThisTest tt = new ThisTest();
System.out.println(tt.num);
}
}
public class ThisTest {

//带有static
//主方法
public static void main(String[] args) {

//调用doSome方法
ThisTest.doSome();

//调用doSome方法
doSome();

//调用doOther方法
//【编译错误】
//ThisTest.doOther(); //实例方法必须先创建对象,通过“引用.”的方式访问

//doOther是实例方法
//实例方法调用必须有对象的存在
//以下代码表示的含义:调用当前对象的doOther方法
//但是由于main方法当中没有this,所以以下方法不能调用。
//doOther(); //编译错误
//this.doOther(); //编译错误
ThisTest tt = new ThisTest();
tt.doOther();

}

//带有static
public static void doSome(){
System.out.println("do some!");
}

//实例方法
public void doOther(){
//this表示当前对象
System.out.println("do other!");
}

//run是实例方法,调用run方法的一定是有对象存在的。
//一定是先创建了一个对象才能调用run方法
public void run(){
//在大括号中的代码执行过程当中一定是存在“当前对象”的。
//也就是说这里一定是有“this”的。
System.out.println("run execute!");

//doOther是一个实例方法,实例方法调用必须有对象的存在
//以下代码表示的含义就是:调用当前对象的doOther方法
doOther();  //this.大部分情况下都是可以省略的
//this.doOther();  
}
}

 

6.3 this关键字的使用2

this可以用在哪里:
1、可以使用在实例方法地当中,代表当前对象 【语法格式:this.
2、可以使用在构造方法当中,通过当前的构造方法调用其它的构造方法 【语法格式:this(实参);

重点:this()这种语法只能出现在构造函数第一行

Date.java

public class Date {
//属性
private int year;
private int month;
private int day;

//构造函数
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
/*
需求:当程序员调用以下无参数的构造方法时候,默认创建的日期是1970-1-1
*/
public Date() {
/*
this.year = 1970;
this.month = 1;
this.day = 1;
*/
//以上代码可以通过调用另一个构造方法来完成
//但前提是不能创建新的对象,以下代码表示创建了一个全新的对象
//new Date(1970, 1, 1);

//需要采用以下的语法来完成构造方法的调用,
//这种方式不会创建新的java对象,但同时又可以达到调用其它构造方法。
this(1970, 1, 2);
}


//setter and getter
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMouth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}

//对外提供一个方法可以将日期打印输出到控制台
//实例方法
public void print(){
System.out.println(this.year + "年" + this.month + "月" + this.day + "日");
}
}

DateTest.java

public class DateTest {

	public static void main(String[] args) {

		//创建日期对象1
		Date time1 = new Date();
		time1.print();
		
		//创建日期对象2
		Date time2 = new Date(2022, 6 ,6);
		time2.print();
	}
}

 

6.4 this关键字综合使用

Test1.java

public class Test {

	//带有static的方法
	public static void method1(){
		//调用doSome
		//完整方式的调用
		Test.doSome();
		//省略方式的调用
		doSome();
		
		//调用doOther
		//完整方式调用
		Test t = new Test();
		t.doOther();
		//省略方式调用
		
		//访问i
		//完整的方式访问
		System.out.println(t.i);
		//省略的方式访问
	}
	
	//没有static的方法
	public void method2(){
		//调用doSome
		//完整方式的调用
		Test.doSome();
		//省略方式的调用
		doSome();
		
		//调用doOther
		//完整方式调用
		this.doOther();
		//省略方式调用
		doOther();

		//访问i
		//完整的方式访问
		System.out.println(this.i);
		//省略的方式访问
		System.out.println(i);

	}	
	
	//主方法
	public static void main(String[] args) {
		//要求在这里编写程序调用method1
		//使用完整方式调用
		Test.method1();
		//使用省略方式调用
		method1();
		
		//要求在这里编写程序调用method	2
		//使用完整方式调用
		Test t = new Test();
		t.method2();
		//使用省略方式调用
	}
	
	//带有static的变量
	int i = 10;
	
	//带有static的方法
	public static void doSome(){
		System.out.println("do some!");
	}
	
	//没有static的方法
	public void doOther(){
		System.out.println("do other!");
	}

}

Test2.java

什么时候程序在运行的时候出现空指针异常呢?
	空引用访问实例相关的数据,因为实例相关的数据就是对象相关的数据,这些数据在访问的时候,必须有对象的参与,当空引用的时候,对象不存在,访问这些实例数据一定会出现空指针异常。
		
实例相关的包括:
	实例变量
	实例方法


public class Test {
		
	public static void main(String[] args) {
		Test.doSome();
		doSome();
		
		Test t = new Test();
		t.doSome();
		
		//引用是空
		t = null;
		//带有static的方法,其实既可以采用类名的方式访问,也可以采用引用的方式访问
		//但是即使采用引用的方式去访问,实际上执行的时候和引用指向的对象无关。
		//在myeclipse中开发的时候,使用引用的方式访问带有static的方法,程序会出现警告。
		//所以带有static的方法还是建议使用“类名.”的方式访问。
		t.doSome();  //这里不会出现空指针异常
	}
	
	//带有static的方法,需要使用“类名.”的方式访问
	public static void doSome(){
		System.out.println("do Some!");
	}

}

 

7 static关键字

7.1 static关键字引入

Chinese.java

package com.bjpowernode.javase.test008;

/*
	“中国人”类
*/

public class Chinese {
	
	//身份证号 【每一个对象的身份证号不同】
	//实例变量
	String id;
	
	//姓名 【每一个对象的姓名不同】
	//实例变量
	String name;
	
	//国籍 【每一个对象由于都是由“Chinese类”实例化的,所以每一个中国人的国籍都是“中国”】
	//无论通过Chiese类实例化多少个java对象,这些java对象的国籍都是“中国”
	//实例变量 【实例变量是一个java对象就有一份,100个java对象,就有100个country】,分析这种
	//实例变量存储java对象内部,在堆内存当中,在构造方法执行的时候初始化。
	//所有的中国人的国籍都是“中国”,这里声明为实例变量显然是不合适的,太浪费内存空间,没必要让每一个对象都保存一份“国籍”内存。
	String country;
	
	//构造函数
	public Chinese(){
		/*
		this.id = null;
		this.name = null;
		this.country = null;
		*/
	}
	
	public Chinese(String id, String name, String country){
		this.id = id;
		this.name = name;
		this.country = country;
	}
}

ChineseTest.java

package com.bjpowernode.javase.test008;

public class ChineseTest {

	public static void main(String[] args) {

		//创建中国人对象1
		Chinese zhangsan = new Chinese("1", "zhangsan", "中国");
		System.out.println(zhangsan.id + "," + zhangsan.name + "," + zhangsan.country);
		
		//创建中国人对象2
		Chinese lisi = new Chinese("2", "lisi", "中国");
		System.out.println(lisi.id + "," + lisi.name + "," + lisi.country);

	}

}

 

7.2 static关键字使用

什么时候成员变量声明为实例变量呢?
	- 所有对象都有这个属性,但是这个属性的值会随着对象的变化而变化 【不同对象的这个属性值不同】
	
什么时候成员变量声明为静态变量呢?
	- 所有对象都有这个值,并且所有对象的这个属性的值是一样的,建议定义为静态变量,节省内存的开销
	
静态变量在类加载的时候初始化,内存在方法区中开辟。访问的时候不需要创建对象,直接“类名.静态变量名”的方式访问。

关于java中的static关键字:
	1、static英语单词翻译为静态的
	2、static修饰的方法是静态方法
	3、static修饰的变量是静态变量
	4、所有static修饰的元素都称为静态的,都可以使用“类名.”的方式访问,当然也可以使用“引用.”的方式访问 【但是不建议】
	5、static修饰的所有元素都是类级别的特征,和具体的对象无关。

Chinese.java

public class Chinese {
	
	//身份证号 【每一个对象的身份证号不同】
	//实例变量
	String id;
	
	//姓名 【每一个对象的姓名不同】
	//实例变量
	String name;
	
	//国籍 【所有对象的国籍一样,这种特征属于类级别的特征,可以提升为整个模板的特征,可以在变量前添加static关键字修饰】
	//静态变量,静态变量在类加载的时候初始化,不需要创建对象,内存就开辟了。
	//静态变量存储在方法区内存当中。
	static String country = "中国";
	
	//构造函数
	public Chinese(){
		/*
		this.id = null;
		this.name = null;
		this.country = null;
		*/
	}
	
	public Chinese(String id, String name){
		this.id = id;
		this.name = name;
	}
}

ChineseTest.java

public class ChineseTest {

	public static void main(String[] args) {

		//创建中国人对象1
		Chinese zhangsan = new Chinese("1", "zhangsan");
		System.out.println(zhangsan.id + "," + zhangsan.name + "," + Chinese.country);
		
		//创建中国人对象2
		Chinese lisi = new Chinese("2", "lisi");
		System.out.println(lisi.id + "," + lisi.name + "," + Chinese.country);
		
		System.out.println(Chinese.country);
		System.out.println(zhangsan.country);
		zhangsan = null;
		//所有静态的数据都是可以采用“类名.”,也可以采用“引用.”,但是建议采用“类名.”的方式访问。
		//采用“引用.”的方式访问时候,即使引用是null,也不会出现空指针异常。因为访问静态的数据不需要对象的存在。
		System.out.println(zhangsan.country);
		
	}
}

 

7.3 static静态代码块

1、语法格式:
	static{
		java语句;
	}
	
2、静态代码块在类加载时执行,并且只执行一次。

3、静态代码块在一个类中可以编写多个,并且遵循自上而下的顺序依次执行。

4、静态代码块的作用是什么?怎么用?用在哪儿?什么时候用?
	- 这当然和具体的需求有关,例如项目中要求在类加载的时候/时刻执行代码完成日志记录。那么这段记录日志的代码就可以编写到静态代码块当中,完成日志记录。
	- 静态代码块是java为程序员准备的一个特殊时刻,这个特殊的时刻被称为类加载时刻。若希望在此刻执行一段特殊的程序,这段程序可以直接放到静态代码块当中。
	
5、通常在静态代码块当中完成预备工作,先完成数据的准备工作,例如:初始化连接池,解析XML配置文件...

public class StaticTest01 {

	static{
		System.out.println("类加载-->1");
	}
	
	static{
		System.out.println("类加载-->2");
	}
	
	static{
		System.out.println("类加载-->3");
	}
	
	public static void main(String[] args) {
		System.out.println("main begin");
		
	}

}
实例语句块/代码块 【了解内容,使用的非常少】
	1、实例代码块可以编写多个,也是遵循自上而下的顺序依次执行
	2、实例代码块在构造方法执行之前执行,构造方法执行一次,实例代码块对应执行一次
	3、实例代码块也是java语言为程序员准备一个特殊的时机,这个	特殊时机被称为:对象初始化时机	

 

7.5 static静态代码块

public class MainTest {

	//public表示公开的,在任何位置都是可以访问的
	//static表示静态的,使用“类名.”的方式即可访问,不需要创建对象,就可以调用main方法
	//void表示main方法执行结束之后不返回任何值
	//main是main方法的方法名
	//(String [] args)是main方法的形式参数列表

	public static void main(String[] args) {
		main(10);
		main("xiaohong");
	}
	
	public static void main(int i){
		System.out.println(i);
	}
	
	public static void main(String args){
		System.out.println(args);
	}

}
/*
	方法什么时候定义为静态的?
		方法描述的是动作,当所有对象执行这个动作的时候,最终产生影响是一样的,那么这个动作已经不再属性某一个对象的动作了,可以将这个动作提升为类级别的动作,模板级别的动作。
		
	静态方法中无法直接访问实例变量和实例方法。 
	
	大多数方法都定义为实例方法,一般一个行为或者一个动作在发生的时候,都需要对象的参与。但是也有例外,例如:大多数“工具类”中的方法都是静态方法,因为工具类就是方便编程,为了方便方法的调用,自然不需要new对象是最好的。
*/

public class StaticTest {

	//实例变量
	int i = 100;
	
	//实例方法
	public void doSome(){
		
	}
	
	//静态方法
	public static void main(String[] args) {
		//System.out.println(i);
		//doSome();
		
		StaticTest st = new StaticTest();
		System.out.println(st.i);
		st.doSome();
		
		//使用数据工具类
		System.out.println(MathUtil.sumInt(10, 20));
	}
}

/*
	总结:
		class 类{
			静态代码块;
			实例代码块;
			
			静态变量;
			实例变量;
			
			构造方法;
			
			静态方法;
			实例方法;
		}	
*/
/*
	数学工具类
*/

public class MathUtil {

	public static int sumInt(int a, int b){
		return a + b;
	}
	
	public static int divide(int a , int b){
		return a / b;
	}

 

8 继承

8.1 继承基本知识

Account.java

 public class Account {
	
	private String actno;
	private double balance;
		
	public Account() {
		super();
	}

	public Account(String actno, double balance) {
		super();
		this.actno = actno;
		this.balance = balance;
	}

	public String getActno() {
		return actno;
	}

	public void setActno(String actno) {
		this.actno = actno;
	}

	public double getBalance() {
		return balance;
	}

	public void setBalance(double balance) {
		this.balance = balance;
	}	
}

CreditAccount.java

public class CreditAccount extends Account{

	private double credit;
	
	public CreditAccount() {
		super();
	}

	public double getCredit() {
		return credit;
	}

	public void setCredit(double credit) {
		this.credit = credit;
	}	
}

ExtendsTest.java

/*
关于java语言当中的继承:
	1、继承是面向对象三大特征之一,大三特征分别是:封装、继承,多态
	
	2、继承基本的作用是:代码复用。但是继承最重要的作用是:有了继承才有了以后方法的覆盖和多态机制
	
	3、继承的语法格式:
		[修饰符列表] class 类名 extends 父类名{
			类体	
		}
		
	4、java语言当中的继承只支持单继承,一个类不能同时继承继承很多类,只能继承一个类。在C++和python中支持多继承
	
	5、关于继承中的一些术语:
		B类继承A类,其中:
			A类称为:父类、基类、超类、superclass
			B类称为:子类、派生类、subclass
			
	6、在java语言当中子类继承父类都继承哪些数据呢?
		* 私有的不支持继承
		* 构造方法不支持继承
		* 其它数据都可以被继承
		
	7、虽然java语言中只支持单继承,但是一个类也可以间接继承其它类,例如:
		C extends A{}
		B extends A{}
		A extends T{}
		C直接继承B类,但是C类间接继承T、A类。
		
	8、java语言中假设一个类没有显示继承任何类,该类默认继承JavaSE库当中提供的java.lang.Object类。
	
	java语言中任何一个类都有Object类的特征。		
*/

public class ExtendsTest {

	//MyEclipse快捷键:查找类型【Open type】:ctrl + shift + t	 
	//MyEclipse快捷键:查找资源【Open Resources】: ctrl + shift + r
	public static void main(String[] args) {
		
		ExtendsTest et = new ExtendsTest();
		String s = et.toString();
		System.out.println(s);
		
		CreditAccount act = new CreditAccount();
		act.setActno("act-001");	
		act.setBalance(-1000.0);
		act.setCredit(0.99);
		
		System.out.println(act.getActno() + "," + act.getBalance() + act.getCredit());
	}

}

ExtendsTest2.java

public class ExtendsTest2 {
	
	public static void main(String[] args){
		C c = new C();
		c.doSome();  //这里调用的doSome方法是从B类中继承过来的doSome方法。
	}
}


class A{
	public void doSome(){
		System.out.println("do some");
	}
}

class B extends A{}

class C extends B{}

8.2 方法的覆盖

Animal.java

//动物类

public class Animal {

	//动物都是可以移动的
	public void move(){
		System.out.println("动物在移动");
	}
}

Car.java

//猫科类

public class Car extends Animal{
	
	public void move(){
		System.out.println("猫在歨猫步");
	}
}

Bird.java

//飞禽类

public class Bird extends Animal{

	public void move(){
		System.out.println("鸟儿在飞翔");
	}
}

YingWu.java

public class YingWu extends Bird {

	//这里的move方法覆盖的是Bird当中的move方法 
	public void move() {
		System.out.println("鹦鹉飞不起来");
	}
}

OverrideTest01.java

/*
	关于java语言中方法的重载:
		1、方法重载又称为Overload
		
		2、方法重载什么时候使用?
			当在同一个类当中,方法完成的功能是相似的,建议方法名相同,这样方便程序员的编程,就像在调用一个方法似的。代码美观。
			
		3、什么条件满足之后构成方法重载?
			* 在同一个类当中
			* 方法名相同
			* 参数列表不同:类型、顺序、个数
						
		4、方法重载和什么无关?
			* 方法的返回值类型无关
			* 方法的修饰符列表无关
		
		
	关于java语言当中的方法覆盖:
		1、方法覆盖又称为方法重写,英语单词:override【官方的】/overwrite
		
		2、什么时候使用方法重写?
			当父类中的方法已经无法满足当前子类的业务需求,子类有必要将父类中继承过来的方法进行重新编写,这个重新编写的过程称为方法重写/方法覆盖。
			
		3、什么条件满足之后方法会发生重写呢? 【代码满足什么条件之后,就构成方法的覆盖呢?】
			* 方法重写发生在具有继承关系的父类之间
			* 方法重写的时候:返回值类型相同、方法名相同、形参列表相同
			* 方法重写的时候:访问权限不能更低,可以更高
			* 方法重写的时候:抛出异常不能更多,可以更少。
		
		4、建议方法重写的时候尽量复制粘贴。不要编写,容易出错,导致没有产生覆盖。
		
		5、注意:
			私有方法不能继承,所以不能覆盖
			构造方法不能继承,所以不能覆盖
			静态方法不存在覆盖。【讲完多态之后解释】
			覆盖只针对方法,不含属性。
			
*/

public class OverrideTest01 {
	
	public static void main(String[] args){
		
		//创建动物对象
		Animal a = new Animal();
		a.move(); 
		
		//创建猫科类动物对象
		Car c = new Car();
		c.move();
		
		//创建飞禽类的动物
		Bird b = new Bird();
		b.move();
		
		YingWu y = new YingWu();
		y.move();
	}
}
 

 

9 多态

9.1 多态基础

Test.java

/*
关于java语言当中的多态语法机制:
1、Animal、Cat、Bird三个类之间的关系:
Cat继承Animal
Bird继承Animal
Cat和Bird之间没有任何关系

2、面向对象的三大特征:封装、继承、多态

3、关于多态中涉及到的几个概念:
* 向上转型(upcasting)
子类型 --> 父类型
又被称为:自动类型转换。
* 向下转型(downcasting)
父类型 --> 子类型
又被称为:强制类型转换。 【需要加强制类型转换符】
* 需要记忆
无论是向上转型还是向下转型,两种类型之间必须要有继承关系。
*/

public class Test {

public static void main(String[] args) {

//以前编写的程序
Animal a1 = new Animal();
a1.move();

Cat c1 = new Cat();
c1.move();

Bird b1 = new Bird();
b1.move();

//使用多态语法机制
/*
1、Animal和Cat之间存在继承关系,Animal是父类,Cat是子类
2、Cat is a Animal
3、new Cat()创建的对象的类型是Cat,a2这个引用数据类型是Animal,可见它们进行了类型,子类型转换成父类型,称为向上转型/upcasting,或者称为自动类型转换。
4、Java中允许这种语法:父类型引用指向子类型对象
*/
Animal a2 = new Cat();
//Bird b2 = new Cat(); //编译报错,因为两种类型之间不存在继承关系。无法向上或者向下转型
/*
1、java程序永远都分为编译阶段和运行阶段。
2、先分析编译阶段,再分析运行阶段,编译无法通过,根本是无法运行的。
3、编译阶段编译器检查a2这个引用的数据类型为Animal,由于Animal.class字节码当中有move()方法,所以编译通过了。这个过程我们称为静态绑定,编译阶段绑定。只有静态绑定成功之后才有后续的运行。
4、在程序运行阶段,JVM堆内存当中真实创建的对象是Cat对象,那么以下程序在运行阶段一定会调用Cat对象的move()方法,此时发生了程序的动态绑定,运行阶段绑定。
5、无论Cat类有没有重写move方法,运行阶段一定调用的是Cat对象的move方法,因为底层真实对象就是Cat对象。
6、父类型引用指向子类型对象这种机制导致程序存在编译阶段和运行阶段有两种不同的形态/状态,这种机制可以称为一种多态语法机制。
*/
a2.move();

/*
分析以下程序为什么不能调用?
因为编译阶段编译器检查到a2的类型是Animal类型,从Animal.class字节码文件当中查找catchMouse()方法,最终没有找到该方法,导致静态绑定失败,没有绑定成功,也就是编译失败了。
*/
//a2.catchMouse();

/*
需求:
假设想让以下的对象执行catchMouse()方法,怎么办?
a2是无法直接调用的,因为a2的类型Animal,Animal中没有catchMouse()方法。
我们可以将a2强制类型转换为Cat类型
a2的类型是Animal(父类),转换成Cat类型(子类),被称为向下转型/downcasting/强制类型转换
注:向下转型也需要两种类型之间必须有继承关系。不然编译报错。强制类型转换需要加强制类型转换符
什么时候需要使用向下转型呢?
当调用的方法或者访问的属性是子类型中特有的,在父类型当中不存在,必须向下转型。
*/
Cat c2 = (Cat)a2;
c2.catchMouse();

//父类型引用指向子类型对象 【多态】
Animal a3 = new Bird();
/*
1、以下程序编译是没有问题的,因为编译器检查到a3的数据类型是Animal,Animal和Cat之间存在继承关系,并且Animal是父类型,Cat是子类型,父类型转换成子类型是向下转型,语法合格
2、程序虽然编译通过了,但是程序在运行阶段会出现问题,因为JVM堆内存当中真实存在的对象是Bird类型,Bird对象无法转换成Cat对象,因为两种类型之间不存在任何继承关系,此时出现了著名异常:
"java.lang.ClassCastException"
类型转换异常,这种异常总量在“向下转型的时候”会发生。
*/

//Cat c3 = (Cat)a3;
/*
1、以上异常只有在强制类型转换的时候会发生,也就是说“向下转型存在隐患”(编译过了,但是运行错了)

2、向上转型只要编译通过,运行一定不会出问题。Animal a = new Cat();

3、向下转型编译通过,运行可能错误:Animal a3 = new Bird(); Cat c3 = (Cat)a3;

4、怎么避免向下转型出现的ClassCaseException呢?
使用instanceof运行符可以避免出现以上的异常。

5、instanceof运算符怎么用?
5.1、语法格式:
引用 instanceof 数据类型名
5.2、以上运算符的执行结果类型是布尔类型,结果可能是true/false
5.3、关于运算结果true/false:
假设:(a instanceof Animal)
true表示:
a这个引用指向的对象是一个Animal类型。
false表示:
a这个引用指向的对象不是一个Animal类型。

6、Java规范中要求:在进行强制类型转换之前,建议采用instanceof运算符进行判断,避免ClassCastException异常的发生。这是一种编程好习惯。
*/
if(a3 instanceof Cat){  //a3是一个Cat类型的对象
Cat c3 = (Cat)a3;
//调用子类型对象中特有的方法
c3.catchMouse();
}else if(a3 instanceof Bird){  //a3是一个Bird类型的对象
Bird b2 = (Bird)a3;
//调用子类型对象中特有的方法
b2.fly();
}
}

}

Animal.java

//动物类

public class Animal {

public void move(){
System.out.println("动物在移动");
}
}

Cat.java

//猫类

public class Cat extends Animal {

//重写父类中继承过来的方法
public void move(){
System.out.println("猫在走猫步");
}

//不是从父类中继承过来的方法
//这个方法是子类对象特有的行为 【不是说所有的动物都能抓老鼠】
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}

Bird.java

//鸟儿类

public class Bird extends Animal {

//重写从父类中继承过来的方法
public void move(){
System.out.println("鸟儿在飞");
}

/*
子类对象特有的行为/动作
*/
public void fly(){
System.out.println("Bird fly!");
}
}

Test2.java

public class Test2 {

public static void main(String[] args) {

//父类型引用指向子类型对象
//向上转型
Animal a1 = new Cat();
Animal a2 = new Bird();

//向下转型 【只有当访问子类对象当中特有的方法】
if(a1 instanceof Cat){
Cat c1 = (Cat)a1;
}

if(a2 instanceof Bird){
Bird b1 = (Bird)a2;
}

}

}

Test3.java

public class Test3 {

public static void main(String[] args) {

int i = 10;
int j = 20;
int retValue = sumInt(i, j);
System.out.println(retValue);
}

public static int sumInt(int i, int j){
int c = i + j;
int b = 15;
int result = divide(c, b);
return result;
}

private static int divide(int c, int b) {
int a = c / b;
return a;
}

}

 

9.2 多态的使用

多态在实际开发中的作用,以下以主人喂养宠物为例说明多态的作用:
1、分析:主人喂养宠物这个场景要实现需要进行类型的抽象
- 主人 【类】
- 主人可以喂养宠物,所以主人有喂养这个动作
- 宠物 【类】
- 宠物可以吃东西,所以宠物有吃东西的这个动作

2、面向对象编程的核心:定义好类,然后将类实例化为对象,给一个环境驱使一下,让各个对象之间协作起来形成一个系统

3、多态的作用是什么?
降低程序的耦合席,提高程序的扩展力。
能使用多态尽量使用多态。
父类型引用指向子类型对象。

核心:面向抽象编程,尽量不要面向具体编程

Cat.java

//宠物小猫

public class Cat extends Pet {

//小猫爱吃鱼
public void eat(){
System.out.println("小猫正在吃鱼");
}
}

Dog.java

//宠物小狗

public class Dog extends Pet{

/*
宠物小狗喜欢吃骨头
*/
public void eat(){
System.out.println("小狗正在啃骨头");
}
}

Snake.java

//新的宠物
public class Snake extends Pet{

public void eat(){
System.out.println("蛇吞象!");
}
}

Pet.java

/*
宠物
*/

public class Pet {

//所有的宠物都可以吃东西
public void eat(){

}
}

Master.java

/*
主人
*/

//这种方法没有使用java语言当中的多态机制,存在的缺点:Master的扩展力很差,因为只要加一个新的宠物,Master类就需要添加新的方法。
/*
public class Master {

//喂养宠物的方法
public void feed(Cat c){
c.eat();
}

public void feed(Dog d){
d.eat();
}
}
//Master和Cat、Dog这两个类型的关联程序很高,耦合度很高,扩展度差
*/

//降低程序的耦合类【解耦合】,提高程序的扩展力【软件开发的一个很重要的目标】
public class Master{

//Master主人类面向的是一个抽象的Pet,不再面向具体的宠物
//提倡:面向抽象编程,不要面向具体编程。
//面向抽象编程的好处是,耦合度低,扩展力强。
public void feed(Pet pet){
pet.eat();
}
}

Test.java

public class Test {

public static void main(String[] args) {

//创建主人对象
Master zhangsan = new Master();

//创建猫对象
Cat tom = new Cat();

//主人喂养猫
zhangsan.feed(tom);

//创建小狗
Dog erHa = new Dog();

//主人喂养小狗
zhangsan.feed(erHa);

//创建蛇对象
Snake mangShe = new Snake();
//主人喂养
zhangsan.feed(mangShe);
}

}

 

10 final

FinalTest01.java

/*
关于java语言当中的final关键字:
1、final是一个关键字,表示最终的,不可变的。
2、final修饰的类无法被继承
3、final修饰的方法无法被覆盖
4、final修饰的变量一旦赋值之后,不可重新赋值
5、final修饰的实例变量,必须手动赋值,不能采用系统默认值
6、final修饰的引用,一旦指向某个对象之后,不能再指向其它对象,那么被指向的对象无法被垃圾回收器回收
7、final修饰的实例变量,一般和static联合使用,被称为常量。

关于myeclipse怎么链接源码?
打开某个.class字节码文件,当没有看到源码的时候:
点击“Change Attached Source”:
- Workspace 【源码在当前工作区当中】
- External File 【源码在某个压缩包当中】
- External Folder 【源码在某个目录当中】

以后尽量所有的程序都链接源码,没有源码从网上找...
养成看源码的好习惯。

对于以后大家所学习的类库,一般都是包括三个部分的:
- 源码 【可以看源码来理解程序】
- 字节码 【程序开发过程中使用就是字节码】
- 帮助文档 【对源码的解释说明,方便开发】
*/

public class FinalTest01 {

public static void main(String[] args) {

int i = 10;
System.out.println(i);
i = 20;
System.out.println(i);

final int k = 100;
//编译报错:无法为最终变量k分配值
//k = 200;

final int m;
m = 200;
//编译错误:无法为最终变量m分配值
//m = 300;

}

}

A.java

public final class A {

}

B.java

/*
public class B extends A {

}
*/

C.java

public class C {

public final void m1(){

}
}

D.java

public class D extends C {

/*
public void m1(){

}
*/
}

FinalTest02.java

public class FinalTest02 {

//成员变量之实例变量
//实例变量有默认值 + final修饰的变量一旦赋值不能重新赋值
//综合考虑,java语言最终规定实例变量使用final修饰之后,必须手动赋值
//final int age; //编译错误

//第一种解决方案
final int age = 18;

//第二种解决方案
final int num;
public FinalTest02(){
this.num = 200;
}

//以上的两种解决方案:其实本质上就是一种方式,都是在构造方法执行过程当中给实例变量赋值。

public static void main(String[] args) {

final int a;
a = 100;
//不可二次赋值
a = 200;
}

}

FinalTest04.java

public class FinalTest04 {

public static void main(String[] args) {

System.out.println(Chinese.COUNTRY);
System.out.println(Math.PI);
}

}

class Math{
public static final double PI = 3.1415926;
}

//中国人
class Chinese{
//国籍
//每一个中国人的国籍都是中国,而且国籍不会发生改变,为了防止国籍被修改,建议加final修饰。
//final修饰的实例变量是不可变的,这种变量一般和static联合使用,被称为“常量”
//常量的定义语法格式:public static final 类型 常量名 = 值;
//java规范中要求所有常量的名字全部大写,每个单词之间使用下划线连接
public static final String COUNTRY = "中国";

}

 

11 import、package

Test01.java

/*
关于java语言当中的包机制:
1、包又称为package,java中引入package这种语法机制主要是为了方便程序的管理。不同功能类被分门别类放到不同的软件包当中,查找比较方便,管理比较方便,易维护。

2、怎么定义package呢?
- 在java源程序的第一行编写package语句。
- package只能编写一个语句。
- 语法结构:
package 包名;

3、包名的命名规范:
公司的域名倒序 + 项目名 + 模块名 + 功能名
采用这种方式重名的概率较低,因为公司域名具有全球唯一性。
例如:
com.bjpowernode.oa.user.service;
org.apache.tomcat.core;

4、包名要求全部小写,包名也是标识符,必须遵守标识符的命名规则。

5、一个包将来对应一个目录。

6、使用了package机制之后,应该怎么编译?怎么运行?
- 使用了package机制之后,类名不再是Test01了,类名是:com.bjpowernode.javase.day11.Test01
- 编译:javac java源文件路径 (在硬盘一生成一个class文件:Test01.class)
- 手动方式创建目录,将Test01.class字节码文件放到指定的目录下
- 运行:java com.bjpowernode.javase.day11.Test01
- 另一种方式(编译 + 运行)
* 编译:
javac -d 编译之后存在路径 java源文件的路径
例如:将F:\Hello.java文件编译之后放到C:\目录下
javac -d C:\ F:\Hello.java
javac -d . *.java  
将当前路径中*.java编译之后存放到当前目录下。
* 运行:JVM的类加载器ClassLoader默认从当前路径下加载。
保证DOS命令窗口的路径先切换到com所在的路径,执行:java com.bjpowernode.javase.day11.Test01



*/

package com.bjpowernode.javase.day11;  //4个目录【目录之间使用.隔开】

public class Test01
{
public static void main(String[] args){
System.out.println("Test01's main method execute!");
}
}

Test02.java

package com.bjpowernode.javase.day11;

public class Test02
{
public static void main(String[] args){

//完整类名是:com.bjposernode.javase.day11.Test01
com.bjpowernode.javase.day11.Test01 t = new com.bjpowernode.javase.day11.Test01();
System.out.println(t);

//可以省略包名,因为Test01和test02在同一个软件包当中
Test01 tt = new Test01();
System.out.println(tt);

}
}

Test03.java

package com.bjpowernode;

public class Test03
{
public static void main(String[] args){

//创建test01对象
//以下代码编译错误:当省略包名之后,会在当前包下找test01
//实际上编译器去找:com.bjpowernode.Test01.class文件了。
//这个类不存在,编译报错
//test01 tt = new Test01();
//System.out.println(tt);

//修改以上错误
//包名不要省略,添加包名
//结论:什么时候前边的包名可以省略呢?Test03和test01在同一个包下的时候不需要加包名
com.bjpowernode.javase.day11.Test01 tt = new com.bjpowernode.javase.day11.Test01();
System.out.println(tt);
}
}

Test04.java

package org.apache;

/*
import语句用来完成导入其它类,同一个包下的类不需要导入,不在同一个包下需要手动导入。

import语法格式:
import 类名;
import 包名.*;

import语句需要编写到package语句之下,class语句之上
*/

//import com.bjpowernode.javase.day11.Test01;
import com.bjpowernode.javase.day11.*
import java.util.Date;

public class Test03
{
public static void main(String[] args){

com.bjpowernode.javase.day11.Test01 tt = new com.bjpowernode.javase.day11.Test01();
System.out.println(tt);

//以下程序可以,就是麻烦一些。
Test01 x = new Test01();
System.out.println(x);

//java.lang.*; 不需要手动引入,系统自动引入。
//lang: language语言包,是java语言的核心类,不需要手动引入。
String s = "abc";
System.out.println(s);

//直接编写以下代码编译错误,因为Date类没有找到
//Date d = new Date();

//修改错误
//方式一
java.util.Date d = new java.util.Date();
//方式二:使用import语句之后import java.util.Date;
Date d = new Date();
}
}

/*
最终结论:
什么时候需要import?
* 不是java.lang包下,并且不在同一个包下的时候,需要使用import进行引入。
*/

 

12 访问控制权限

访问控制权限修饰符:
1、访问控制权限修饰符来控制元素的访问范围
2、访问控制权限修饰符包括:
public 表示公开的,在任何位置都可以访问
protected   同包,子类
缺省 子类
private     表示私有的,只能在本类中访问
3、访问控制权限修饰符可以修饰类、变量、方法...
4、当某个数据只希望子类使用,使用protected进行修饰
5、修饰符的范围:
private < 缺省 < protected < public

Test01.java

package com.bjpowernode.javase.test005;

public class Test01 {

public static void main(String[] args) {

User u = new User();
System.out.println(u.i);
System.out.println(u.j);
}

}

User.java

package com.bjpowernode.javase.test005;

public class User {

//受保护的
protected int i = 10;

//缺省的
int j = 20;

private void m1(){

}

public void m2(){

}

protected void m3(){

}

void m4(){

}
}

UserTest.java

package com.bjpowernode.javase.test006;

import com.bjpowernode.javase.test005.User;

public class UserTest {

public static void main(String[] args) {
User u = new User();
System.out.println(u.i);  //编译报错
System.out.println(u.j);  //编译报错
}

}

Driver.java

package com.bjpowernode.javase.test006;

import com.bjpowernode.javase.test005.User;

public class Driver extends User {

public void m(){
System.out.println(i);  
System.out.println(j);  //编译报错
}
}

Student.java

package com.bjpowernode.javase.test006;

class Student {

}

Customer.java

package com.bjpowernode.javase.test006;

/*
类只能采用public和缺省的修饰符进行修饰。 【内部类除外】
*/

public class Customer {

}

 

 

 

posted @   路走  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示