this & static & 代码块
this关键字
三个作用:
- 调用本对象成员属性
- 调用本对象成员方法
- 代表本实例对象
先从this调用属性说起
class Man{
String name;
int age;
public Man(String n, int a) { //参数与成员属性名称不一样
name = n;
age = a;
}
public void sing(){
System.out.println("我会唱歌");
}
public void dance(){
System.out.println("我会跳舞");
}
}
public class Main {
public static void main(String[] args) {
Man man = new Man("小王", 18);
System.out.println("姓名:"+man.name+" : "+"年龄:"+man.age);
}
}
运行结果:
成功构造姓名为“小王”,年龄为18的一个男人
如果我们将构造方法的形式参数名改成和成员属性名一模一样
执行结果如下:
失败了!!!
为什么失败呢
因为构造方法里面的两条语句是没有意义的语句,就相当于1=1,2=2
为什么会这样?
因为代码块中,大括号{}中相同的变量名指的都是同一个对象,因此压根儿就没有成员属性的事儿,所以就没有初始化成功,姓名为null,年龄为默认的0
怎么样解决呢?
答案:this关键字 调用成员属性
我们将构造方法做以下修改:
利用this.来调用属性
运行结果正确!
this调用方法
- 调用构造方法 this();
- 调用普通方法 this.方法名();
调用构造方法
什么时候才会调用构造方法?
new 的时候
所以this.调用构造方法,只会出现在构造方法中
这里有一条铁律
如果要使用this调用构造方法,this();必须是第一条语句
构造方法互相调用时,一定要避免造成死循环(递归构造器调用)
static关键字
如果类的所有变量都具有同样的属性,那么这个属性就可以用static修饰
比如Person 这个类,每个人都有自己的国家,假如是中国民国,那么他们的所属国家都是一样的,而如今我们的国家改名为中华人民共和国,产品用户现有一亿人,我们就要对一亿人的国家属性进行修改,很明显一个一个改会让程序员疯掉的
那么 只要我们用static修饰国家这个属性,当修改一个对象的国家属性时,所有对象的国家属性都会变,因此可解决上述问题
代码如下:
class Person{
private String name;
private int age;
static private String contry;
public Person(String name, int age, String contry) {
this.name = name;
this.age = age;
this.contry = contry;
}
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 getContry() {
return contry;
}
public void setContry(String contry) {
this.contry = contry;
}
public String getInfo(){
return "姓名:"+this.getName()+" 年龄:"+this.getAge()+" 国家:"+this.getContry();
}
}
public class Main {
public static void main(String[] args) {
Person person1 = new Person("代号001",20,"中华民国");
Person person2 = new Person("代号002",21,"中华民国");
Person person3 = new Person("代号003",22,"中华民国");
System.out.println(person1.getInfo());
System.out.println(person2.getInfo());
System.out.println(person3.getInfo());
System.out.println("修改第一个人的国家属性之后");
person1.setContry("中华人民共和国");
System.out.println("-----------------");
System.out.println(person1.getInfo());
System.out.println(person2.getInfo());
System.out.println(person3.getInfo());
}
}
运行结果:
所有人的国家都改变了
而我们如果不给contry用static修饰的话
运行结果是这样的:
只能修改一个人的国家,就很麻烦
所以static的方便性就显而易见了
这是内存分析:
static修饰的属性存储在全局数据区内,所以一个对象更改,全部对象的都会跟着更改
上面的代码部分是不规范的
对于static修饰属性的访问,应该由权限最高者(类)来进行,而非单个对象,所以正确的更改国家的写法应该是:直接由类名称调用
由上面的代码做上图修改会遇到一个问题,contry是static的,但同时也被private修饰,那么在主方法中就不可能访问到contry这个变量,对此我们有两种解决方式:
- 取消对contry的private修饰
- 将setContry()方法用static修饰,主方法通过该方法来修改contry值
static 在类中定义,但是不受类实例化对象控制,也就是说,没有实例化对象的时候,static修饰的属性也可以直接使用
在进行设计开发的时候,首选非static属性,在考虑用到公共信息存储的时候才用到static属性。非static属性在实例化对象之后才能使用,而static属性不管有没有实例化对象,都可以直接使用
static修饰方法
在上面的第二个解决方式中就涉及到了用static修饰方法
- static方法只能调用static属性或者static方法
- 非static方法允许调用static属性或者static方法
原因很简单:static定义的属性和方法都可以在没有实例化对象的情况下使用,而非static定义的属性和方法不能在没有实例化对象的情况下使用
代码块
在程序中,使用的大括号{}括起来的结构就称为代码块
根据位置和定义的关键字不同,可分为普通代码块、构造块、静态块、同步代码块
普通代码块
在方法中被{}包围的代码,例如 for循环,if分支语句等等,都可以叫做一个代码块
在这些代码块中,{}还有一个作用?
在程序开发中,一个方法中是不允许出现同名变量的,但是,{}可以将方法进行结构拆分,以防止变量名相同
例如:
public class Main {
public static void main(String[] args) {
fun();
}
public static void fun(){
for (int j = 0; j < 10; j++) {
int i = 1;
System.out.println("i = "+i+j);
}
int i = 10;
System.out.println(i);
}
}
从运行结果中我们可以知道,程序是没有报错,正常运行的
因为{}将方法结构划分了,在{}中代码执行完之后,自动将int i这个变量销毁,所以后续就没有i这个变量,因此可以在后面重新定义一个变量i
构造代码块
定义在类中,优先于构造方法执行,并且实例化新对象的时候都会执行一次
class Book{
private String name;
public Book(String name) {
this.name = name;
System.out.println("构造方法 执行");
}
{ //构造块
System.out.println("构造块 执行");
}
}
public class Main {
public static void main(String[] args) {
new Book("三国演义");
new Book("西游记");
new Book("红楼梦");
}
}
运行结果:
结果:每一次都是代码块先执行,构造方法后执行
静态代码块
使用关键字static 定义的代码块
分为两种:主类中定义,非主类中定义
class Book{
private String name;
public Book(String name) {
this.name = name;
System.out.println("构造方法 执行");
}
static {
System.out.println("静态代码块 执行");
}
{
System.out.println("构造块 执行");
}
}
public class Main {
public static void main(String[] args) {
new Book("三国演义");
new Book("西游记");
new Book("红楼梦");
}
}
运行结果:
结果:静态代码块优先于构造块,构造方法执行,但是由始至终只会执行一次
主要作用是为类中的static属性初始化
探索
static静态代码块和主类中主方法的执行顺序
public class Main {
static {
System.out.println("静态代码块");
}
public static void main(String[] args) {
System.out.println("主方法");
}
}
答案:
静态代码块优先于主方法执行
代码编译器:IntelliJ IDEA 2020.02