这一节我们看静态在使用过程中应注意的几个细节。
上一节我们在学习成员变量与静态变量的区别时,对于两种变量的调用方式不同时出现了“无法从静态上下文中访问非静态变量”的错误,这个问题我们在以后会经常遇到。那么这是什么问题呢?我们从例子说起,我们把上一节中的Person类中方法printInfo进行静态修饰:
~~~
class Person
{
String name;//姓名,这是一个成员变量
static String country = "中国";//国籍,这是一个静态变量
public static void printInfo()
{
System.out.println(name+":"+country);
}
}
class StaticTest
{
public static void main(String[] args)
{
Person p = new Person();
p.name = "小强";
p.printInfo();
}
}
~~~
结果:
![](https://box.kancloud.cn/2016-05-18_573c41ed38250.jpg)
我们看到了一个和上一节完全相同的错误,而当我们把方法进行修改:
~~~
public static void printInfo()
{
System.out.println(":"+country);
}
~~~
结果:
![](https://box.kancloud.cn/2016-05-18_573c41ed4d5c7.jpg)
我们看到当把printInfo方法中的非静态变量name去掉之后,程序正常运行,因此我们可以总结出static关键字使用中的一个常见问题,即:
**第一个细节:静态方法中不能调用非静态成员,只能调用静态成员.**这是由于我们知道静态成员是随着类的加载而存在,是先于对象存在的,而非静态的成员变量是随着对象的创建而存在,所以当我们在静态方法中调用非静态成员时,还没有创建对象,当然就不存在非静态变量.比如我们上面的例子,静态方法printInfo和静态变量country都会随着Person类的加载而加载,而成员变量name只有随着Person对象的创建才会存在,当我们在静态方法中直接调用name时,此时根本就不存在,当然会出错.
当然对于这个细节,也可以说是静态方法的一个局限性.非静态方法既可以访问静态成员,也可以访问非静态成员.
我们再看下一个比较常见的问题.
**第二个细节:静态方法中不可以使用this或者super关键字.**原因当然可以用静态的特点解释,super我们还没有学习,这里暂不说明,就拿this关键字来说,我们说this代表对象,那么当我们在静态方法中使用this时,this代表的就是当前类的实例,而静态方法和类是一起存在的,而该类的对象并不存在,所以会出错.我们看一个例子:
~~~
class Person
{
String name;
static String country = "中国";
public static void printInfo()
{
System.out.println(this.name+":"+country);
}
}
~~~
结果:
![](https://box.kancloud.cn/2016-05-18_573c41ed5e64e.jpg)
我们很清楚的就看到这是不合法的.
**第三个细节:主函数是静态的.**这个我们大家肯定都不陌生,我们从开始学习就在搞main函数,它的正确格式是:
~~~
public static void main(String[] args)
~~~
那么我们再来看一个例子:
~~~
class StaticTest
{
int num = 4;
public static void main(String[] args)
{
printNum();
}
public void printNum()
{
System.out.println(num);
}
}
~~~
结果:
![](https://box.kancloud.cn/2016-05-18_573c41ed731ce.jpg)
我们会发现我们没有用好第一个细节,所以我们进一步修改:
~~~
class StaticTest
{
int num = 4;
public static void main(String[] args)
{
printNum();
}
public static void printNum()
{
System.out.println(num);
}
}
~~~
结果:
![](https://box.kancloud.cn/2016-05-18_573c41ed85af2.jpg)
哦,还有一个非静态成员变量,再一次修改:
![](https://box.kancloud.cn/2016-05-18_573c41ed9a5e2.jpg)
这个过程真麻烦哦,那么我们是不是要在主函数中调用的成员都是静态的呢?如果真是这样,那么要对象干什么呢?我们知道主函数是程序的入口,对于面向对象语言,那么主函数也就对象访问的入口,是指挥对象工作的,如果没有对象不知道有多么可怕啊.
我们之前学习了两种调用方式,一种是通过类名调用,而另一种方式就是通过对象调用,那么我们为了规避静态的局限性,我们把上面的方法进行非静态化,并且通过对象去调用:
~~~
class StaticTest
{
int num = 4;
public static void main(String[] args)
{
new StaticTest().printNum();
}
public void printNum()
{
System.out.println(num);
}
}
~~~
并且程序正常运行了.
**第四个细节:在本类中,非静态成员前面省略的是this,而在静态成员前面省略的却是类名.**比如上面的代码,实际上在Person类中,成员变量name前面省略的this,即this.name,而在静态变量country前面省略的类名Person,即Person.country,这一点我们在以后的使用多注意就可以了.
- 前言
- 1.1 基本常识
- 1.2 Java语言概述
- 1.3 Java语言的环境搭建
- 1.4 Java程序开发之初体验--Hello World
- 2.1 关键字
- 2.2 标识符
- 2.3 注释
- 2.4 常量
- 2.5 进制扫盲
- 2.6 变量和数据类型(1)
- 2.7 变量和数据类型(2)
- 2.8 运算符
- 3.1 if语句
- 3.2 switch语句
- 3.3 while和do-while语句
- 3.4 for语句
- 3.5 for循环的嵌套
- 3.6 break语句与continue语句
- 4.1 函数的定义
- 4.2 定义函数的两个明确
- 4.3 函数的内存加载过程
- 4.4 函数的重载
- 5.1 数组的定义
- 5.2 数组的内存分配及特点
- 5.3 数组操作中常见问题
- 5.4 数组常用操作(1)
- 5.5 数组常用操作(2)
- 5.6 二维数组
- 6.1 面向对象的概述
- 6.2 类与对象的关系
- 6.3 对象的内存体现
- 6.4 成员变量与局部变量
- 6.5 类类型参数与匿名对象
- 6.6 基本数据类型参数与引用数据类型参数的传递过程
- 6.7 封装
- 7.1 构造函数概述与默认构造函数
- 7.2 构造函数与一般函数的区别
- 7.3 构造函数的重载
- 7.4 构造函数的内存加载
- 7.5 构造函数需要注意的几个细节
- 7.6 this关键字的原理
- 7.7 this关键字的细节与应用
- 8.1 static关键字之特点
- 8.2 成员变量与静态变量的区别
- 8.3 static关键字使用的注意细节
- 8.4 main函数的解析与细节
- 8.5 static关键字的使用场景
- 8.6 静态的内存加载
- 8.7 静态代码块
- 8.8 构造代码块
- 9.1 继承
- 9.2 单继承与多重继承
- 9.3 子父类中成员变量特征体现