目录
tips
static出现的场合
- static + 属性 -> 静态属性
- static + 方法 -> 静态方法
- static + 类内非成员方法内的方法块 -> 静态代码块
- 静态成员是类的所有对象共享的,一个对象更新了静态成员,则所有对象的该静态成员均变化,这一点很好理解,因为只有一份,所有对象均指向这一份。
- 静态属性与静态方法均是与类绑定的,随着类的第一次加载而产生,直至类销毁才被回收。
- 同是因为随着类的第一次加载而产生,故外部可以在没有实例化对象时就通过类名直接调用,也正是因为这样,static修饰的静态方法其内部无法直接访问同一类的非静态成员,这点很好理解,因为静态成员与对象绑定,调用静态方法的时候还不一定有类的实例,同理,this代表对象实例,故就算访问同类的静态成员,也只能通过类名.静态成员或直接静态成员,而不能this.静态成员。
- static + 类内非成员方法内的方法块 -> 静态代码块,凡是静态只要记住是和类绑定的即可,随着类的第一次加载而产生,故静态代码块只会被调用一次,即类加载的时候。
- 非静态成员则可以访问非静态成员以及静态成员,因为非静态成员与对象绑定,自然可以访问到;静态成员与类绑定,既然对象生成了,自然类已经加载过了,与类绑定的静态成员自然也已经存在了。
static不能出现的场合
- 不存在static + 类
- 不存在static + 方法内局部变量
代码块
- 执行顺序:静态代码块 -> 构造代码块 -> 构造方法
- 静态代码块 和 构造代码块同一类别按顺序执行,构造方法按参数传入选择执行。
- 静态代码块 和 类绑定,类第一次加载的时候,执行每一个静态代码块。
- 构造代码块和对象绑定,实例化的时候调用每个构造代码块。
- 构造方法与对象绑定,实例化的时候选择调用构造方法。
下面贴一点点代码
Code.java
package com.imooc.code;
class Code{
//创建Code类的构造块(构造块)
{
System.out.println("Code的构造代码块");
}
//创建Code类的静态代码块(静态代码块)
static{
System.out.println("Code的静态代码块");
}
//创建Code类的构造方法(构造方法)
public Code(){
System.out.println("Code的构造方法");
}
}
CodeBlock.java
package com.imooc.code;
public class CodeBlock{
// 创建CodeBlock的构造块
{
System.out.println("CodeBlock的构造代码块");
}
//创建CodeBlock的静态代码块
static{
System.out.println("CodeBlock的静态代码块");
}
//创建CodeBlock的构造方法
public CodeBlock(){
System.out.println("CodeBlock的构造方法");
}
public static void main(String[] args){
//编写代码测试运行优先顺序,运行结果参见效果图
System.out.println("CodeBlock的主方法"); // 主方法可以自动进入,但也表示了类的创建,所以运行了静态代码块
System.out.println("产生Code类的实例对象");
Code code = new Code();
System.out.println("产生CodeBlock类的实例对象");
CodeBlock codeBlock = new CodeBlock();
}
}
打印:
第一行的打印:因为主方法在CodeBlock.java中,运行主方法也意味着该类的加载,故打印:CodeBlock的静态代码块,后面我们再执行CodeBlock codeBlock = new CodeBlock();, 就没打印CodeBlock的静态代码块,也可以看出静态代码块随类的加载而执行,且只会执行一次。
CodeBlock的静态代码块
CodeBlock的主方法
产生Code类的实例对象
Code的静态代码块
Code的构造代码块
Code的构造方法
产生CodeBlock类的实例对象
CodeBlock的构造代码块
CodeBlock的构造方法
=================================附=================================
附1
一、封装的实现
封装
- 将类的某些信息隐藏在类内部,不允许外部程序直接访问
- 通过该类提供的方法来实现对隐藏信息的操作和访问
- 隐藏对象的信息
- 留出访问的接口
特点:
- 只能通过规定的方法访问数据
- 隐藏类的实例细节,方便修改和实现
实现步骤
- 修改属性的可见性(设为private)
- 创建getter/setter方法(设为public,用于属性的读写)
- 在getter/setter方法中加入属性控制语句(对属性值的合法性进行判断)
小tips:构造函数也可以调用set方法来进行赋值操作。
二、包
包的作用:
- 管理java文件
- 解决同名文件冲突
包的定义
- java中一个包下不允许存在同名的类
- 定义包:package 包名,package com.imooc.animal
- 必须放在Java源文件中的第一行
- 一个Java源文件中只能有一个package语句
- 包名全部英文小写
- 推荐命名:域名倒叙 + 模块 + 功能
- 建议每个包内存储信息功能单一
包的加载
- 建议采用import 包名.类名的方式加载提高效率
- 加载类的顺序与import导入语句的位置无关
- 导入包中全部类:import com.imooc.*
- 导入包中指定类:import com.imooc.animal.Cat
下面的Cat cat=new Cat(),这边的Cat是animal包下的Cat类,尽管mechanics包下也有Cat类,但因为animal.Cat指引更加具体,所以是animal下的Cat。
package com.imooc.test; //定义包
//import com.imooc.animal.*; //加载com.imooc.animal包下的所有类
import com.imooc.animal.Cat; //加载com.imooc.animal包下指定的Cat类
import com.imooc.mechanics.*; // 加载类的顺序跟import导入语句的位置无关
//import com.imooc.*; // import 包名.* 只能访问指定包名下的类,无法访问子包下的类
public class Test {
public static void main(String[] args){
Cat cat = new Cat();
// CatTest catTest = new CatTest();
//直接加载com.imooc.animal.CatTest
com.imooc.animal.CatTest catTest = new com.imooc.animal.CatTest();
com.imooc.mechanics.Cat cat1 = new com.imooc.mechanics.Cat();
}
}
三、static关键字
static表示静态信息
静态成员:
- 类对象共享
- 类加载时产生,销毁时释放,生命周期长
静态成员访问方式:
- 对象.成员
- 类.成员
其中Cat类的price是静态变量,从Cat.price=4000可以看出类的静态成员,无需实例化对象,可以直接在类外通过类调用。构造函数是实例化对象的时候自动调用的,故这句话也不涉及构造函数。
Cat的带参构造函数如下,这边构造函数前没有static关键字,但是可以访问类的静态成员。
public Cat(String name, int month){
setName(name);
setMonth(month);
price = 900;
System.out.println("有参构造:" + this.name + "是一只愉快的宠物喵!");
}
public class Test {
public static void main(String[] args){
Cat.price = 4000;
System.out.println(Cat.price);
Cat.eat();
Cat one = new Cat("花花", 2);
System.out.println(one.getName() + one.price );
one.price = 1000;
Cat two = new Cat("凡凡", 2);
two.price = 150;
System.out.println(one.getName() + one.price );
System.out.println(two.getName() + two.price );
}
}
=================================附=================================
附2
关于封装应用中的常见问题
1.若不用封装,再要调用的普通成员方法中编写相关限制代码,实现避免在主方法中所调用属性及方法的值被非法篡改,这样不也可以么,为什么一定要用封装?
在面向对象的的设计思想中,封装可以理解为是一种利用抽象的函数接口实现细节信息的包装隐藏的方式。我们可以把封装认为是一个保护屏障,防止该类的私密代码和数据被外部类定义的代码随机访问和修改。简单来说,就是“按我的规则,才能玩我的游戏”。而在隐藏信息的同时,我们还要注意“职责单一”原则的应用,也就是“各司其职”。
若只从功能实现的角度来说,当然可以将限制代码写在任意的功能实现方法中,但是试想,若一个类中,有10个功能性方法中需要对某一属性进行相同的设定,是设置一次方便,还是设置10次更方便安全呢?
因此,适当的封装可以让代码更容易理解与维护,也加强了安全性。调用者不能随意通过“变量名.属性名”的方式来修改类中的私密数据信息;同时,在使用的时候,也只需直接调用封装后的方法即可,无需再操心细节处理。
2.get/set用两个方法实现取值、赋值,放在一个方法离不是更简单?是否可以改成别的名字?
若仅仅是为了实现功能,那么,无论是写在一个方法里,还是用其他名字命名方法都是ok的,但,在基于面向对象的编程思想中,更推荐大家用get/set方法分别实现“取值”和“赋值”的功能,让他们各司其职,也更加通俗易懂,毕竟当业务越来越复杂,团队协作的时候,约定俗成会比各有千秋更有价值。
3.有了get/set方法,为什么还需要带参构造方法?或者说,在构造方法中直接写if...else...判断限制输入输出结果不行么?为什么要多写两个方法?
构造方法与get/set方法作用是不同的构造方法只能在创建对象时进行调用,若在对象构建完成后,再想对某些属性进行赋值和取值,就无法再次应用构造方法啦。因此两者并不冲突,可以应用带参构造在对象初始化时进行某些属性的设置,也可以通过get/set方法,在对象构建完成后进行后续修订。
static关键字的应用--静态属性
static是 Java中常用的关键字,代表“全局”或者“静态”的意思。关于static的特征,可以理解为:方便在没有创建对象的情况下来进行某些操作。通常可用于修饰成员变量和方法,也可以形成静态代码块。可将需频繁操作、通用型信息设置、公共组件封装等操作设置为“静态”。应用一:static + 成员变量 vs 成员变量
概念:
- 静态成员:用static修饰的成员变量,通常也称为静态成员、静态属性、类成员、全局属性等。
- 非静态成员:没有被static修饰的成员变量,也称为叫做非静态成员、实例变量,实例成员,对象成员、对象属性等。
特征:
静态成员:
- 静态成员是属于整个类的,由类所进行维护,仅在类初次加载时会被初始化,在类销毁时回收。
- 通过该类实例化的所有对象都共享类中静态资源,任一对象中信息的修订都将影响所有对象。
- 由于静态成员在类加载期间就已经完成初始化,存储在Java Heap(JDK7.0之前存储在方法区)中静态存储区,因此优先于对象而存在,可以通过类名和对象名两种方式访问。
非静态成员:
- 非静态成员属于对象独有,每个对象进行实例化时产生各自的成员,随着对象的回收而释放。
- 对象对各自成员信息的修订不影响其他对象
- 只能通过对象名访问。
应用:
可以将频繁调用的公共信息、期望加快运行效率的成员设置为静态。但需注意,由于其生命周期长,即资源占用周期长,要慎用。
static关键字的应用------静态方法
概念:
- 静态方法:用static 修饰的成员方法,通常也称为静态方法、类方法、全局方法等。
- 非静态方法:没有被static修饰的方法,也称作非静态方法、实例方法、对象方法等。
特征:
- 与静态成员相似,静态方法属于整个类的,由类所进行维护,优先于对象而存在,因此可以通过类名和对象名两种方式访问,有因此在静态方法中无法直接访问同类中的非静态成员。
静态方法同类内总结:
- 静态方法中可以通过“类名.成员”或“成员”的方式访问类内静态成员、静态方法
- 不允许直接访问本类中的非静态成员、非静态方法
- 可以通过实例化产生本类对象,通过“对象.成员”的方式访问本类内非静态成员、非静态方法。
静态方法类外总结:
- 类外可应用“类名.成员方法”或“对象名.成员方法”的方式访问非私有静态方法
- 应用“对象名.成员方法”时会出现警告,但不影响程序运行。
非静态方法同类内总结:
- 非静态方法可以通过“类名.成员”或“成员”或“this.成员”的方式访问类内静态成员/静态方法
- 应用“this.静态成员/静态方法”时会出现警告,但不影响程序运行。
- 不允许在方法内部定义静态局部变量。
非静态方法类外总结
- 只能对象.成员,不能类名.成员
static + 代码块 vs 代码块(一)
概念:
- 静态代码块:被static修饰的,定义在类内部,用{}括起的代码段。
- 构造代码块:没有被static修饰的,定义在类内部,用{}括起的代码段。
- 普通代码块:定义在方法内部,用{}括起的代码段。
特征:
- 静态代码块:
- 只能出现在类内,不允许出现在方法内。
- 可以出现多次,按顺序在类加载时执行。
- 无论该类实例化多少对象,只执行一次。
- 构造代码块:
- 可以在类内出现多次,按顺序在每个对象实例化时执行。
- 执行优先级:晚于静态代码块,高于构造方法。
- 每次执行对象实例化时,均会执行一次。
- 普通代码块:
- 可以在方法内出现多次,按顺序在方法调用时执行。
应用:
- 静态代码块:基于性能优化的考量,多适用于需要在项目启动时执行一次的场景,譬如项目资源整体加载等。
- 构造代码块:多适用于类中每个对象产生时都需要执行的功能封装。与构造方法的区别在于,构造方法是在new执行时有选择性的调用带参或者无参构造,而构造代码块则是,在每个对象实例化时都一定会执行。
- 普通代码块:适用于在方法内进行代码功能拆分。
static + 代码块 vs 代码块(二)
- 执行优先级:静态代码块>构造代码块>构造方法
- 执行次数:静态代码块只执行1次;构造代码块、构造方法随对象实例化个数而定
- 不能在静态代码块中直接对非静态成员赋值。
- 可以在构造代码块中直接操作静态和非静态成员。
- 不能在静态代码块声明静态成员,可以声明非静态成员。
- 静态代码块中声明的成员,在外部无法进行访问
- 普通代码块在方法内顺序执行,各自作用范围独立。
- 方法内定义的局部变量,作用范围为:自定义位置起,至方法结束。在此期间,不允许方法中普通代码块内存在局部变量的声明。
引用数据类型应用——成员属性
通过前面的学习,我们知道Java的类中可以包含属性和方法,其中,属性可以使用基本数据类型(譬如:int,float,double等)定义,也可以使用引用数据类型(譬如:String,数组,自定义类等)定义。
下面将从多角度对比总结,应用引用数据类型声明属性时的特点和注意事项。
作用:
- 引用数据类型:完成实例化后,可借由该类型对象获取其中非私有成员。
- 基本数据类型:无需初始化,只能操作对应类型具体数值。
初始值:
- 引用数据类型:未进行实例化时为null;进行实例化后,将依据对应的构造方法完成初始成员信息设置。
- 基本数据类型:无需初始化,各类型有各自默认值(譬如:int是0,double是0.0等)
调用方式:
Ps:此时指在类内方法中访问,暂不考虑static修饰的情况
- 引用数据类型:如未进行实例化,方法中调用对象非私有成员时会报空指针异常;当进行初始化后,可借由对象访问其非私有成员信息。
- 基本数据类型:可直接调用获取具体数值
参考:慕课网-Java工程师课程