1. static
Veuillez d'abord jeter un œil au programme suivant :
public class Hello{ public static void main(String[] args){ //(1) System.out.println("Hello,world!"); //(2) } }
Après avoir vu ce programme, il sera familier à la plupart des personnes qui ont étudié Java. Même si vous n’avez pas appris Java mais que vous avez appris d’autres langages de haut niveau, comme le C, vous devriez être capable de comprendre la signification de ce code. Il affiche simplement "Bonjour tout le monde" et n'a aucune autre utilité. Cependant, il montre l'utilisation principale du mot-clé statique.
Au point 1, nous définissons une méthode statique nommée main, ce qui revient à dire au compilateur Java que cette méthode peut être utilisée sans créer d'objet de ce type. Savez-vous encore comment vous gérez ce programme ? Généralement, nous tapons la commande suivante sur la ligne de commande (le soulignement signifie une saisie manuelle) :
javac Hello.java
java Bonjour
Bonjour tout le monde !
C'est le processus que vous exécutez. La première ligne utilise Compilons le Hello. java. Après l'exécution, si vous regardez le fichier actuel, vous constaterez qu'il existe un fichier Hello.class supplémentaire, qui est le bytecode binaire Java généré dans la première ligne. La deuxième ligne est la manière la plus courante d'exécuter un programme Java. Les résultats d'exécution sont comme vous pouvez vous y attendre. En 2, vous vous demandez peut-être pourquoi il est nécessaire de sortir ainsi. D'accord, décomposons cette déclaration. (Si vous n'avez pas installé la documentation Java, veuillez vous rendre sur le site officiel de Sun pour parcourir l'API J2SE) Tout d'abord, System est une classe principale située dans le package java.lang. Si vous regardez sa définition, vous trouverez ceci. line: public static final PrintStream out; Ensuite, allez plus loin et cliquez sur le lien hypertexte PrintStream. Sur la page METHOD, vous verrez un grand nombre de méthodes définies. Recherchez println, et il y aura une ligne comme celle-ci :
public void. println (Chaîne x).
D'accord, maintenant vous devriez comprendre pourquoi nous l'appelons ainsi. out est une variable statique de System, elle peut donc être utilisée directement, et la classe à laquelle out appartient a une méthode println.
Méthode statique
Habituellement, une méthode est définie comme statique dans une classe, ce qui signifie que cette méthode peut être appelée sans objet de cette classe. Comme indiqué ci-dessous :
class Simple{
static void go(){
System.out.println("Go...");
}
}
public class Cal{
public static void main(String[] args ){
Simple.go();
}
}
L'appel d'une méthode statique est "nom de classe. nom de méthode". L'utilisation des méthodes statiques est très simple, comme indiqué ci-dessus. D'une manière générale, les méthodes statiques fournissent souvent des utilitaires pour d'autres classes de l'application. Un grand nombre de méthodes statiques dans les bibliothèques de classes Java sont définies à cet effet.
Variables statiques
Les variables statiques sont similaires aux méthodes statiques. Toutes ces instances partagent cette variable statique, ce qui signifie que seul un bloc d'espace de stockage est alloué lorsque la classe est chargée. Tous ces objets peuvent contrôler ce bloc d'espace de stockage. Bien sûr, final est une autre affaire. Regardez le code ci-dessous :
class Value{ static int c=0; static void inc(){ c++; } } class Count{ public static void prt(String s){ System.out.println(s); } public static void main(String[] args){ Value v1,v2; v1=new Value(); v2=new Value(); prt("v1.c="+v1.c+" v2.c="+v2.c); v1.inc(); prt("v1.c="+v1.c+" v2.c="+v2.c); } }
Les résultats sont les suivants :
v1.c=0 v2.c=0
v1.c=1 v2.c=1
Cela peut prouver qu'ils partagent une zone de stockage. Les variables statiques sont quelque peu similaires au concept de variables globales en C. Il vaut la peine d'explorer la question de l'initialisation des variables statiques. Nous modifions le programme ci-dessus :
class Value{ static int c=0; Value(){ c=15; } Value(int i){ c=i; } static void inc(){ c++; } }
class Count{ public static void prt(String s){ System.out.println(s); } Value v=new Value(10); static Value v1,v2; static{ prt("v1.c="+v1.c+" v2.c="+v2.c); v1=new Value(27); prt("v1.c="+v1.c+" v2.c="+v2.c); v2=new Value(15); prt("v1.c="+v1.c+" v2.c="+v2.c); } public static void main(String[] args){ Count ct=new Count(); prt("ct.c="+ct.v.c); prt("v1.c="+v1.c+" v2.c="+v2.c); v1.inc(); prt("v1.c="+v1.c+" v2.c="+v2.c); prt("ct.c="+ct.v.c); }}
Les résultats d'exécution sont les suivants :
v1.c=0 v2.c=0 v1.c=27 v2.c=27 v1.c=15 v2.c=15 ct.c=10 v1.c=10 v2.c=10 v1.c=11 v2.c=11 ct.c=11
Ce programme démontre diverses fonctionnalités de l'initialisation statique. Si vous êtes nouveau sur Java, les résultats pourraient vous surprendre. Vous pourriez être dérouté par les accolades après l'électricité statique. La première chose que je veux vous dire est que les variables définies statiquement auront priorité sur toutes les autres variables non statiques, quel que soit l'ordre dans lequel elles apparaissent. Comme le montre le programme, bien que v apparaisse avant v1 et v2, le résultat est que v1 et v2 sont initialisés avant v. Après static{ se trouve un morceau de code utilisé pour initialiser explicitement les variables statiques. Ce code ne sera initialisé qu'une seule fois, lorsque la classe est chargée pour la première fois. Si vous pouvez lire et comprendre ce code, cela vous aidera à comprendre le mot-clé statique. En matière d'héritage, les variables statiques de la classe parent seront initialisées en premier, puis celles de la sous-classe, et ainsi de suite. Les variables non statiques ne font pas l'objet de cet article et ne seront pas abordées en détail ici. Veuillez vous référer à l'explication dans Think in Java.
Classe statique
Habituellement, une classe ordinaire n'est pas autorisée à être déclarée statique, seule une classe interne le peut. À l'heure actuelle, la classe interne déclarée comme statique peut être utilisée directement comme une classe normale sans instancier de classe externe. Comme indiqué dans le code suivant :
public class StaticCls{ public static void main(String[] args){ OuterCls.InnerCls oi=new OuterCls.InnerCls(); } } class OuterCls{ public static class InnerCls{ InnerCls(){ System.out.println("InnerCls"); } } }
Le résultat de sortie sera comme prévu :
InnerCls
Le même que la classe ordinaire. Pour d'autres utilisations des classes internes, veuillez vous référer aux chapitres pertinents de Think in Java, qui ne seront pas expliqués en détail ici.
2. ça et super
在上一篇拙作中,我们讨论了static的种种用法,通过用static来定义方法或成员,为我们编程提供了某种便利,从某种程度上可以说它类似于C语言中的全局函数和全局变量。但是,并不是说有了这种便利,你便可以随处使用,如果那样的话,你便需要认真考虑一下自己是否在用面向对象的思想编程,自己的程序是否是面向对象的。好了,现在开始讨论this&super这两个关键字的意义和用法。
在Java中,this通常指当前对象,super则指父类的。当你想要引用当前对象的某种东西,比如当前对象的某个方法,或当前对象的某个成员,你便可以利用this来实现这个目的,当然,this的另一个用途是调用当前对象的另一个构造函数,这些马上就要讨论。如果你想引用父类的某种东西,则非super莫属。由于this与super有如此相似的一些特性和与生俱来的某种关系,所以我们在这一块儿来讨论,希望能帮助你区分和掌握它们两个。
在一般方法中
最普遍的情况就是,在你的方法中的某个形参名与当前对象的某个成员有相同的名字,这时为了不至于混淆,你便需要明确使用this关键字来指明你要使用某个成员,使用方法是“this.成员名”,而不带this的那个便是形参。另外,还可以用“this.方法名”来引用当前对象的某个方法,但这时this就不是必须的了,你可以直接用方法名来访问那个方法,编译器会知道你要调用的是那一个。下面的代码演示了上面的用法:
public class DemoThis{ private String name; private int age; DemoThis(String name,int age){ setName(name); //你可以加上this来调用方法,像这样:this.setName(name);但这并不是必须的 setAge(age); this.print(); } public void setName(String name){ this.name=name;//此处必须指明你要引用成员变量 } public void setAge(int age){ this.age=age; } public void print(){ System.out.println("Name="+name+" Age="+age);//在此行中并不需要用this,因为没有会导致混淆的东西 } public static void main(String[] args){ DemoThis dt=new DemoThis("Kevin","22"); } }
这段代码很简单,不用解释你也应该能看明白。在构造函数中你看到用this.print(),你完全可以用print()来代替它,两者效果一样。下面我们修改这个程序,来演示super的用法。
class Person{ public int c; private String name; private int age; protected void setName(String name){ this.name=name; } protected void setAge(int age){ this.age=age; } protected void print(){ System.out.println("Name="+name+" Age="+age); } } public class DemoSuper extends Person{ public void print(){ System.out.println("DemoSuper:"); super.print(); } public static void main(String[] args){ DemoSuper ds=new DemoSuper(); ds.setName("kevin"); ds.setAge(22); ds.print(); } }
在DemoSuper中,重新定义的print方法覆写了父类的print方法,它首先做一些自己的事情,然后调用父类的那个被覆写了的方法。输出结果说明了这一点:
DemoSuper:
Name=kevin Age=22
这样的使用方法是比较常用的。另外如果父类的成员可以被子类访问,那你可以像使用this一样使用它,用“super.父类中的成员名”的方式,但常常你并不是这样来访问父类中的成员名的。
在构造函数中
构造函数是一种特殊的方法,在对象初始化的时候自动调用。在构造函数中,this和super也有上面说的种种使用方式,并且它还有特殊的地方,请看下面的例子:
class Person{ public static void prt(String s){ System.out.println(s); } Person(){ prt("A Person."); } Person(String name){ prt("A person name is:"+name); } } public class Chinese extends Person{ Chinese(){ super(); //调用父类构造函数(1) prt("A chinese.");//(4) } Chinese(String name){ super(name);//调用父类具有相同形参的构造函数(2) prt("his name is:"+name); } Chinese(String name,int age){ this(name);//调用当前具有相同形参的构造函数(3) prt("his age is:"+age); } public static void main(String[] args){ Chinese cn=new Chinese(); cn=new Chinese("kevin"); cn=new Chinese("kevin",22); } }
在这段程序中,this和super不再是像以前那样用“.”连接一个方法或成员,而是直接在其后跟上适当的参数,因此它的意义也就有了变化。super后加参数的是用来调用父类中具有相同形式的构造函数,如1和2处。this后加参数则调用的是当前具有相同参数的构造函数,如3处。当然,在Chinese的各个重载构造函数中,this和super在一般方法中的各种用法也仍可使用,比如4处,你可以将它替换为“this.prt”(因为它继承了父类中的那个方法)或者是“super.prt”(因为它是父类中的方法且可被子类访问),它照样可以正确运行。但这样似乎就有点画蛇添足的味道了。
最后,写了这么多,如果你能对“this通常指代当前对象,super通常指代父类”这句话牢记在心,那么本篇便达到了目的,其它的你自会在以后的编程实践当中慢慢体会、掌握。另外关于本篇中提到的继承,请参阅相关Java教程。
三、final
final在Java中并不常用,然而它却为我们提供了诸如在C语言中定义常量的功能,不仅如此,final还可以让你控制你的成员、方法或者是一个类是否可被覆写或继承等功能,这些特点使final在Java中拥有了一个不可或缺的地位,也是学习Java时必须要知道和掌握的关键字之一。
final成员
当你在类中定义变量时,在其前面加上final关键字,那便是说,这个变量一旦被初始化便不可改变,这里不可改变的意思对基本类型来说是其值不可变,而对于对象变量来说其引用不可再变。其初始化可以在两个地方,一是其定义处,也就是说在final变量定义时直接给其赋值,二是在构造函数中。这两个地方只能选其一,要么在定义时给值,要么在构造函数中给值,不能同时既在定义时给了值,又在构造函数中给另外的值。下面这段代码演示了这一点:
import java.util.List; import java.util.ArrayList; import java.util.LinkedList; public class Bat{ final PI=3.14; //在定义时便给址值 final int i; //因为要在构造函数中进行初始化,所以此处便不可再给值 final List list; //此变量也与上面的一样 Bat(){ i=100; list=new LinkedList(); } Bat(int ii,List l){ i=ii; list=l; } public static void main(String[] args){ Bat b=new Bat(); b.list.add(new Bat()); //b.i=25; //b.list=new ArrayList(); System.out.println("I="+b.i+" List Type:"+b.list.getClass()); b=new Bat(23,new ArrayList()); b.list.add(new Bat()); System.out.println("I="+b.i+" List Type:"+b.list.getClass()); } }
此程序很简单的演示了final的常规用法。在这里使用在构造函数中进行初始化的方法,这使你有了一点灵活性。如Bat的两个重载构造函数所示,第一个缺省构造函数会为你提供默认的值,重载的那个构造函数会根据你所提供的值或类型为final变量初始化。然而有时你并不需要这种灵活性,你只需要在定义时便给定其值并永不变化,这时就不要再用这种方法。在main方法中有两行语句注释掉了,如果你去掉注释,程序便无法通过编译,这便是说,不论是i的值或是list的类型,一旦初始化,确实无法再更改。然而b可以通过重新初始化来指定i的值或list的类型,输出结果中显示了这一点:
I=100 List Type:class java.util.LinkedList
I=23 List Type:class java.util.ArrayList
还有一种用法是定义方法中的参数为final,对于基本类型的变量,这样做并没有什么实际意义,因为基本类型的变量在调用方法时是传值的,也就是说你可以在方法中更改这个参数变量而不会影响到调用语句,然而对于对象变量,却显得很实用,因为对象变量在传递时是传递其引用,这样你在方法中对对象变量的修改也会影响到调用语句中的对象变量,当你在方法中不需要改变作为参数的对象变量时,明确使用final进行声明,会防止你无意的修改而影响到调用方法。
另外方法中的内部类在用到方法中的参变量时,此参变也必须声明为final才可使用,如下代码所示:
public class INClass{ void innerClass(final String str){ class IClass{ IClass(){ System.out.println(str); } } IClass ic=new IClass(); } public static void main(String[] args){ INClass inc=new INClass(); inc.innerClass("Hello"); } }
final方法
将方法声明为final,那就说明你已经知道这个方法提供的功能已经满足你要求,不需要进行扩展,并且也不允许任何从此类继承的类来覆写这个方法,但是继承仍然可以继承这个方法,也就是说可以直接使用。另外有一种被称为inline的机制,它会使你在调用final方法时,直接将方法主体插入到调用处,而不是进行例行的方法调用,例如保存断点,压栈等,这样可能会使你的程序效率有所提高,然而当你的方法主体非常庞大时,或你在多处调用此方法,那么你的调用主体代码便会迅速膨胀,可能反而会影响效率,所以你要慎用final进行方法定义。
final类
当你将final用于类身上时,你就需要仔细考虑,因为一个final类是无法被任何人继承的,那也就意味着此类在一个继承树中是一个叶子类,并且此类的设计已被认为很完美而不需要进行修改或扩展。对于final类中的成员,你可以定义其为final,也可以不是final。而对于方法,由于所属类为final的关系,自然也就成了final型的。你也可以明确的给final类中的方法加上一个final,但这显然没有意义。
下面的程序演示了final方法和final类的用法:
final class final{ final String str="final Data"; public String str1="non final data"; final public void print(){ System.out.println("final method."); } public void what(){ System.out.println(str+"n"+str1); } } public class FinalDemo { //extends final 无法继承 public static void main(String[] args){ final f=new final(); f.what(); f.print(); } }
从程序中可以看出,final类与普通类的使用几乎没有差别,只是它失去了被继承的特性。final方法与非final方法的区别也很难从程序行看出,只是记住慎用。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!