1. 访问限制符 public,protected,private,默认;
首先我们要明白工程和工程之间的数据是不能互相传递的。因为一个工程就是一个程序,如果你要实现互相传递的话,那么就涉及到了网络通信了。所以下面讨论的所有的类都是属于同一个工程的。
Public:顾名思义,公有的。如果一个属性和方法在一个类A中建立,那么对于其他类,比如说B类,可以在B类中建立A对象a,然后通过a来使用A类中的属性和方法。当然还可以通过继承A类得到A类中的所有public属性和方法。代码如下:
学生类:
<!--EndFragment-->
package test;
/**
*类说明:
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午1:57:57
*/
public class Student {
public String name;
public int score=10;
public void setName(String name){
this.name = name;
}
}
测试类:
<!--EndFragment-->
package test;
/**
*类说明:测试类
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午1:59:51
*/
public class Test {
public static void main(String args[]) {
Student stu = new Student();//创建Student对象
System.out.println(stu.score);//调用stu.score并且输出,看是否可以使用
stu.setName("Tom");//调用stu.setName()来给name赋值
System.out.println(stu.name);//输出stu.name,看name是否已经赋值
}
}
输出结果:
10
Tom
那么结果表明,public限制的属性和方法在其他类都是可以通过建立对象来访问使用的。
我们再来建立一个学生类的子类大学生类,看是否可以调用学生类的属性和方法。
<!--EndFragment-->
package test;
/**
*类说明:大学生类(对于父类:学生类,没有做任何修改,只是继承而已)
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午2:26:00
*/
public class UNStudent extends Student{
}
好,那么我们再来使用这个大学生类。
package test;
/**
* 类说明:测试类
* @author 彭晨明 E-mail:2294552925@qq.com
* @version 创建时间:2012-2-7下午1:59:51
*/
public class Test {
public static void main(String args[]) {
UNStudent unst = new UNStudent();//创建UNStudent对象
System.out.println(unst.score);//调用unst.score并且输出,看是否可以使用
unst.setName("Bob");//调用UNStudent.setName()来给name赋值
System.out.println(unst.name);//输出unst.name,看name是否已经
}
}
输出结果:
10
Bob
由此结果可知,Student类的子类UNStudent类同样是可以使用Student中定义的属性和方法。
protected:受保护的。这个类有点特殊,如果有这么几个类:A类,B类,C类,D类,E类。A类和B类是同一个包(package)当中的,而C类是另外一个包中的,D类是A类同一个包的子类,E类是A类的不是一个包的子类。那么A类定义的属性和方法对于B类来说,调用的方法和public是一样的,而C类中则不可以调用A类定义的属性和方法。D和E类的调用方法和public也是一样的。
学生类(A类),属于包test:
<!--EndFragment-->
<!--EndFragment--> package test;
/**
*类说明:学生类
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午1:57:57
* */
public class Student {
protected String name;
public int score=10;
public void setName(String name){
this.name = name;
}
}
测试类(B类),和学生类一样,同属包test:<!--EndFragment-->
package test;
/**
* 类说明:测试类
* @author 彭晨明 E-mail:2294552925@qq.com
* @version 创建时间:2012-2-7下午1:59:51
*/
public class Test {
public static void main(String args[]) {
Student stu = new Student();//创建一个学生类
stu.name = "Tom";//名字赋值
System.out.println(stu.name);//输出名字
}
}
运行测试类Test,结果如下:
Tom
说明可以正常输出,即Student中的protected属性name可以被同一个包的其他类使用。
测试类Test1,属于包test1:
package Test1;
import test.Student;//引入test包中的Student类
/**
*类说明:Test1包中的测试类
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午2:47:34
*/
public class Test1 {
public static void main(String args[]){
Student stu = new Student();
stu.name = "Tom";
}
}
运行Test1,结果如下:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The field Student.name is not visible
at test1.Test1.main(Test1.java:13)
结果发现Student.name 是不可见的,也就是说其他包中的类是无法使用Test包中的protected属性和方法。
UNStudent 类(D类),与父类学生类(A类)同属于一个包test,:
package test;
/**
*类说明:大学生类
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午2:26:00
*/
public class UNStudent extends Student{
public static void main(String args[]){
Student stu = new Student ();
stu.name = "Tom";//这里调用Student的protected属性name
System.out.println(stu.name);
}
}
结果如下:
Tom
这就说明A的子类是可以调用A类的protected数据。
UNStudent1 类(E类),属于包test1,继承了包Test中的student类:
package test1;
import test.Student;
/**
*类说明:大学生类
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午2:26:00
*/
public class UNStudent1 extends Student{
public static void main(String args[]){
Student stu = new Student();
stu.name = "Tom";
UNStudent1 stu1 = new UNStudent1 ();
stu1.setName("Tom");
System.out.println(stu1.name);
}
}
这里运行结果后,你会发现如果stu.name不能通过编译,这是因为protected的属性和方法,在其他包中是不能通过父类的对象来调用的,必须要用子类的对象来调用,所以UNStudent的对象可以调用name这个属性。
private:私有的。听这个名字就知道,这个一个很“自私”的限制符,被其修饰的属性和方法是不能被A类的子类来调用,不能被同包中的类调用,更不用说被其他包中的类调用。 它只能在A类中自己使用。如果你一定要使用的话,请看后面的注意事项。
默认(就是属性和方法的前面什么都不写,比如说String name或者 void play()):这个是神马?很多人可能不知道有这个访问限制符。这个平时用的不多,它的作用和protected的相似,同一个包中的protected属性和方法可以互相调用,但是不同的包中protected属性和方法不能互相调用,这个规则对于它的子类同样满足。代码如下:
学生类,属于test包中 :
package test;
/**
*类说明:学生类
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午1:57:57
*/
public class Student {
String name;这个就是默认属性
public void setName(String name){
this.name = name;
}
}
测试类,属于test1包中:
package test1;
import test.Student;
/**
*类说明:Test1包中的测试类
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午2:47:34
*/
public class Test1 {
public static void main(String args[]){
Student stu = new Student();
stu.name = "Tom";
}
}
运行结果如下:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The field Student.name is not visible
at test1.Test1.main(Test1.java:11)
Student.name 是不可见的,也就是说默认属性和方法在其他包中是不可调用的。
那看看它的其他包中的子类:
UNStudent1类,属于包test1,是包test中student类的子类:
package test1;
import test.Student;
/**
*类说明:大学生类
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午2:26:00
*/
public class UNStudent1 extends Student{
public static void main(String args[]){
UNStudent1 stu1 = new UNStudent1 ();
stu1.name ="Tom";
stu1.setName("Tom");
System.out.println();
}
}
运行结果如下:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The field Student.name is not visible
at test1.UNStudent1.main(UNStudent1.java:11)
同样,也是不可以调用的。
1. this,super;
this:this有两个用法,一个是用其来代表调用某个方法或者属性的对象;还有一个就是只能在构造器里来使用,用来调用其他的构造器。
第一种用途,即用其来代表调用某个方法或者属性的对象。代码如下:
package test;
/**
*类说明:学生类
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午1:57:57
*/
public class Student {
private String name;
private int score;
public Student(){
}
public Student(String name, int score){
this.name = name;
this.score = score;
}
public void setName(String name){
this.name = name;
}
}
这些标了黄色的代码中的this就是指调用方法的对象。
第二种用途,即只能在构造器里来使用,用来调用其他的构造器。代码如下:
package test;
/**
*类说明:学生类
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午1:57:57
*/
public class Student {
private String name;
private int score;
public Student(){
this("Tom",12);
}
public Student(String name, int score){
this.name = name;
this.score = score;
}
}
上面代码中this("Tom",12);就是调用下面的另外一个构造器,来完成name和score的赋值,这就可以减少代码量。这里需要注意的是this用来调用另外一个构造器的时候,必须是写在构造器的第一行。
super:同样是两种用法,和this类似,不同的是,super是用来调用父类的方法,属性和构造器的,当然调用构造器是只能在子类的构造器中调用。同样也是必须写在构造器的第一行。因为和this类似,所以代码也就没有写了。不过有个地方需要提个醒,就是当子类使用父类的构造器的时候,默认的加了一句:super();
举例便知:
学生类(父类):
package test;
/**
*
*类说明:大学生类
*
*@author 彭晨明 E-mail:2294552925@qq.com
*
*@version 创建时间:2012-2-7下午2:26:00
*
*/
public class UNStudent extends Student{
public UNStudent(){
System.out.println("B");
}
public static void main(String args[]){
new UNStudent();
}
}
运行下你会惊喜的发现,输出的结果不是B,而是A和B。这是为什么呢?这就是开始所说的在UNStudent的构造器中默认的加了一句super()从而调用了父类的构造器方法。请看代码:
学生类(父类,和上面一样,没有发生改变):
package test;
/**
*类说明:学生类
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午1:57:57
*/
public class Student {
public Student(){
System.out.println("A");
}
}
大学生类(子类):
package test;
/**
*
*类说明:大学生类
*
*@author 彭晨明 E-mail:2294552925@qq.com
*
*@version 创建时间:2012-2-7下午2:26:00
*
*/
public class UNStudent extends Student{
public UNStudent(){
super();
System.out.println("B");
}
public static void main(String args[]){
new UNStudent();
}
}
在这个子类的构造器中添加了super(),再运行发现结果和上面的一样,这也就说明子类的构造器调用了super()。这里还要注意是所有的子类的构造器都会调用父类的无参构造器。
2. final 最后,最终之意。
修饰形参时:是指形参在方法内部不能被修改。
修饰属性时:属性相当于常量,即只能赋值一次的变量。必须要初始化。或者在构造器里面给它赋值。
修饰方法时:方法不能被重写,请注意不是重载,重载是可以的。
修饰类时:类是不能被继承的。比如String类就是final类,所以它是不可以被继承的。
代码如下:
package test;
/**
*类说明:学生类
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午1:57:57
*/
Public final class Student {
private final String name = "Tom";
private int score;
public Student(String name, int score){
this.name = name;//这里会报错,因为上面name在定义的时候已经初始化了,也就是说已经赋值了,而final修饰的属性只能被赋值一次。
this.score = score;
}
public final void setScore(final int score){
this.score = score;
score = 3;//这里会报错,因为final修饰的形参不能在方法内被赋值。
}
public static void main(String args[]){
Student stu = new Student("Tom",100);
System.out.println(stu.score);
}
}
下面我们再来写个类看是否可以继承Student这个类。
package test;
/**
*类说明:大学生类
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午2:26:00
*/
public class UNStudent extends Student{
}
我们会发现,系统报错,说Student这个类是无法被继承的。所以也就是说final修饰的类是无法被继承的。亲,不信的话,自己动手做做吧。。。
3. static 静态的,静止的。这个关键字是最坑人的。用法实在是各种。
l 修饰属性时:该属性会是类类型,当建立该类的对象时,对象不会复制静态属性和静态方法,所以说静态属性又可以称为公有属性。可以说是“牵一发而动全身”。还有调用static修饰的属性时,可以不建立对象。为什么这样说呢?举个例子:
学生类:
package test;
/**
*类说明:学生类
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午1:57:57
*/
public class Student {
public static String name;
public static int score;
}
测试类:
package test;
/**
* 类说明:测试类
* @author 彭晨明 E-mail:2294552925@qq.com
* @version 创建时间:2012-2-7下午1:59:51
*/
public class Test {
public static void main(String args[]) {
Student stu1 = new Student();//创建第一个学生类
stu1.name = "Tom";//给stu1的名字赋值
stu1.score = 12;//给stu1的分数赋值
Student stu2 = new Student();//创建第二个学生类
stu2.name = "Bob";//给stu2的名字赋值
System.out.println("stu1名字:"+stu1.name);
System.out.println("stu1分数:"+stu1.score);
System.out.println("stu2名字:"+stu2.name);
System.out.println("stu2分数:"+stu2.score);
}
}
大家猜猜结果会是什么样子的。
结果会是这样的:
stu1名字:Bob
stu1分数:12
stu2名字:Bob
stu2分数:12
为什么呢?这就是正如我开始说的“牵一发而动全身”,也就是说,当一个static属性被赋值a的时候,那么其他的这个类的对象中的这个属性同时都会被赋值a。这是因为static属性它存储的方式而造成的。它不是存储在对象里,而是存储在那个类里,属于类属性,那么也就说大家使用的是同一个变量。当然会同时发生变化啦。不信的话,那么还有一个方法可以检验下,那么就是下面这个:
System.out.println(stu1.name == stu2.name);
亲,你可以打印下,你会发现它输出一个true。而“==”就是判断两个数的地址是否相同,这样的话,那我们就认为上面那段话是对的咯!还有检验下是否不需要建立对象就可以直接使用属性了:
学生类:
package test;
/**
*类说明:学生类
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午1:57:57
*/
public class Student {
public static String name;
public static int score;
}
测试类:
package test;
/**
* 类说明:测试类
* @author 彭晨明 E-mail:2294552925@qq.com
* @version 创建时间:2012-2-7下午1:59:51
*/
public class Test {
public static void main(String args[]) {
// Student stu1 = new Student();//创建第一个学生类
// stu1.name = "Tom";//给stu1的名字赋值
// stu1.score = 12;//给stu1的分数赋值
Student.name = "Tom";//给stu1的名字赋值
Student.score = 12;//给stu1的分数赋值
Student stu2 = new Student();//创建第二个学生类
stu2.name = "Bob";//给stu2的名字赋值
System.out.println("stu1名字:"+Student.name);
System.out.println("stu1分数:"+Student.score);
System.out.println("stu2名字:"+stu2.name);
System.out.println("stu2分数:"+stu2.score);
}
}
咱们会发现,之前那建立对象的代码被注释掉了,直接使用了Student.name = "Tom";//给stu1的名字赋值。而这样系统没有报错,就是说明这个是可以有的。
l 修饰方法时:这个方法被调用时是不需要对象的。这样就可以解释一个问题了,为什么我们的主函数总是要用一个static来修饰,这是因为我们主函数在执行的时候,还没有建立对象。同时static修饰的方法中使用的属性和方法必须是静态的或者是建立了对象之后,由对象调用。
口说无凭,举例为证:
学生类:
package test;
/**
*类说明:学生类
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午1:57:57
*/
public class Student {
public static String name;
public static int score;
public static void setName(String name){
Student.name = name;
}
}
测试类:
package test;
/**
* 类说明:测试类
* @author 彭晨明 E-mail:2294552925@qq.com
* @version 创建时间:2012-2-7下午1:59:51
*/
public class Test {
public static void main(String args[]) {
Student.setName("Tom");
System.out.println("stu1名字:" + Student.name);
}
}
运行之后,结果如下:
stu1名字:Tom
那么就是说明了static的方法是可以直接没有建立对象而被引用的。
咱们再来看看static静态方法中是否可以不建立对象而调用非静态属性和非静态方法。
package test;
/**
* 类说明:测试类
* @author 彭晨明 E-mail:2294552925@qq.com
* @version 创建时间:2012-2-7下午1:59:51
*/
public class Test {
private int score =100;
private String name;
public void setName(String name){
this.name = name;
}
public static void main(String args[]) {
System.out.println(score);
setName("Tom");
}
}
你会发现这是不可以的。而当建立一个对象后:
package test;
/**
* 类说明:测试类
* @author 彭晨明 E-mail:2294552925@qq.com
* @version 创建时间:2012-2-7下午1:59:51
*/
public class Test {
private int score =100;
private String name;
public void setName(String name){
this.name = name;
}
public static void main(String args[]) {
Test test = new Test();
System.out.println(test.score);
test.setName("Tom");
}
}
这样子的话,编译就可以了。当然如果是静态属性和方法的话,在静态方法中是可以不建立对象用的。还有非静态方法中是可以调用静态属性和方法的。
最后还有一个注意事项:当然如果你要用某种属性的时候,那么还有一种万能的办法,就是你可以在一个类中写个方法用来取得那种属性,这样的话,你就可以随便调用了。例如:
package test;
/**
*类说明:学生类
*@author 彭晨明 E-mail:2294552925@qq.com
*@version 创建时间:2012-2-7下午1:57:57
*/
public class Student {
protected String name;
public void setName(String name){
this.name = name;
}
}
在这个类中就是使用了setName这个方法来使用了name属性,当然如果你想要得到那个属性的话,那么完全可以写个getName的方法。
亲,终于看完了,可以休息会了。。。
<!--EndFragment--> <!--EndFragment-->