java中接口能被java long 初始化化吗?

{"debug":false,"apiRoot":"","paySDK":"/api/js","wechatConfigAPI":"/api/wechat/jssdkconfig","name":"production","instance":"column","tokens":{"X-XSRF-TOKEN":null,"X-UDID":null,"Authorization":"oauth c3cef7c66aa9e6a1e3160e20"}}
{"database":{"Post":{"":{"contributes":[{"sourceColumn":{"lastUpdated":,"description":"","permission":"COLUMN_PUBLIC","memberId":,"contributePermission":"COLUMN_PUBLIC","translatedCommentPermission":"all","canManage":true,"intro":"","urlToken":"c_","id":44504,"imagePath":"4b70deef7","slug":"c_","applyReason":"0","name":"一起来coding","title":"一起来coding","url":"/c_","commentPermission":"COLUMN_ALL_CAN_COMMENT","canPost":true,"created":,"state":"COLUMN_NORMAL","followers":2,"avatar":{"id":"4b70deef7","template":"/{id}_{size}.jpg"},"activateAuthorRequested":false,"following":false,"imageUrl":"/4b70deef7_l.jpg","articlesCount":6},"state":"accepted","targetPost":{"titleImage":"","lastUpdated":,"imagePath":"","permission":"ARTICLE_PUBLIC","topics":[3646],"summary":"接口是Java中的一个重要的概念,很多的时候我们定义一个方法的时候可能并没有想到这个方法应该如何去实现,而是只是想到有这样的方法。实际上接口的作用是定义一个规范,规范了实现这个接口的类都应该具有怎么样的方法。我们可以想象生活中这样的例子:工厂…","copyPermission":"ARTICLE_COPYABLE","translatedCommentPermission":"all","likes":0,"origAuthorId":0,"publishedTime":"T22:30:17+08:00","sourceUrl":"","urlToken":,"id":3327094,"withContent":false,"slug":,"bigTitleImage":false,"title":"Java中的接口、抽象类和事件监听","url":"/p/","commentPermission":"ARTICLE_ALL_CAN_COMMENT","snapshotUrl":"","created":,"comments":0,"columnId":0,"content":"","parentId":0,"state":"ARTICLE_PUBLISHED","imageUrl":"","author":{"bio":"Coding maybe","isFollowing":false,"hash":"9a42c92c02df","uid":681000,"isOrg":false,"slug":"bu-ding-10-95","isFollowed":false,"description":"","name":"布丁","profileUrl":"/people/bu-ding-10-95","avatar":{"id":"8c859ee6c6a3e1f4567ed","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false},"memberId":,"excerptTitle":"","voteType":"ARTICLE_VOTE_CLEAR"},"id":717412}],"title":"Java中的接口、抽象类和事件监听","author":"bu-ding-10-95","content":"接口是Java中的一个重要的概念,很多的时候我们定义一个方法的时候可能并没有想到这个方法应该如何去实现,而是只是想到有这样的方法。实际上接口的作用是定义一个规范,规范了实现这个接口的类都应该具有怎么样的方法。我们可以想象生活中这样的例子:工厂中会有各种各样的生产方法,但是工厂新建的时候我们并不能具体的写出这个方法是如何实现的。不过我们能够大概知道生产中应该遵守怎么样的规范。在这样的场景中,工厂的管理规范其实也就是接口。然后无论是哪个车间的工人,生产什么样的东西,都要遵守工厂的生产规范(也就是实现接口中的抽象方法)。Java中定义接口的关键字是interface,下面是定义接口的格式:public interface 接口名 extends 接口名,....{\n\t//接口中可以定义常量\n\tpublic static fianl 数据类型 常量名=值;\n\t//定义接口中的抽象方法\n\tpublic abstract 方法名(参数列表);\n}\n这里有一个需要注意的地方:1.Java中接口不能实例化对象。(首先接口中没有构造方法,其次接口中的抽象方法并没有方法体,所以接口的实例化是没有意义的。)2.Java中接口的访问修饰符只能是public3.接口中会默认提供public abstract final static 的关键字。(这就是为什么如果接口中直接定义常量和方法不加修饰符也不会报错的原因)一个类实现接口的方式:public class 类名 extends 父类类名 implements 接口名{\n}\n一个类实现了接口之后必须要重写接口中的所有的抽象方法,不然就会报错。前面也说过了,接口的主要作用是提供一种规范,所以在团队开发中会经常使用接口,用来定义一些必须要实现的方法。另外Java中类的继承是单继承,而类却可以实现多个接口,这样就丰富了Java的继承机制。实际上接口的实现,和类的继承很相像,可以说接口的实现是一种特殊的继承关系。这也就是为什么接口中的常量在实现接口的类中可以直接使用的原因。说完了接口我们在来讲讲抽象类,抽象类的实际上也是为程序的开发提供一个规范。抽象类的定义使用的关键字是abstract定义的格式如下:public abstract class 类名{\n\t//可以定义类中的所有内容\n\t//可以定义接口中的所有内容\n} \n所以抽象类实际上可以说是类和接口的结合,抽象类也是不能实例化对象的,抽象类必须有子类来实现其中的抽象方法。了解了接口和抽象类之后,我们可以来看看Java中的事件监听机制。Java的事件监听主要有三个要素:事件源对象,事件监听,事件处理类(事件接口)。先回想一下生活中的一个事件:比如有客人来了,听到敲门的声音,然后我听到敲门声,去开门。这是生活中的一个很简单的场景,这个场景就包含了一个事件的所有要素:首先是事件的事件源对象,敲门的动作是发生在门上,事件源对象就是门。然后我听到了敲门声,说明我一直在监听事件,发现事件源对象上监听的动作开始响应——去开门。开门就是我的事件处理方法。Java中的任何事件的处理都可以用着三个步骤来实现。首先确定事件源对象;然后编写事件处理类,实现事件处理的接口并重写其中的方法;最后给相应的事件源对象添加事件监听方法并指定事件处理类。下面是Java中常用的事件处理类监听方法:addActionListener(ActionListener l);\t监听类似按钮组件上是否有鼠标点击动作的方法或者是监听类似输入框组件上是否有键盘的回车动作的方法,如果有,则捕获动作以及相关的信息,交给\tActionLIstener参数对象进行处理。\t\taddKeyListener(KeyListener l);监听事件源对象上是否有键盘按键按下,释放和敲击动作,如果有则捕获动作以及相关的信息,交给KeyListener参数对象进行处理。\t\t\taddMouseListener(MouseListener l);监听事件源对象上是否有鼠标的进入、按下、释放、点击和离开动作,如果有则捕获动作以及相关的信息,交给MouseListener参数对象进行处理。\t\taddMouseMotionListener(MouseMotionListener l);监听事件源对象上是否有鼠标的移动和拖动动作,如果有则捕获动作以及相关的信息,交给MouseMotionListener参数对象进行处理。\t\taddFocusListener(FocusListener l);监听事件源对象上是否有组件获得或失去键盘焦点动作,如果有则捕获动作以及相关的信息,交给FocusListener参数对象进行处理。\t\taddChangeListener(ChangeListener l);监听事件源对象上的状态是否发生更改,如果有则捕获动作以及相关的信息,交给ChangeListener参数对象进行处理。下面看看事件监听的实例:package Cbs;\n\nimport java.awt.Dimension;\nimport java.awt.FlowLayout;\nimport javax.swing.JButton;\nimport javax.swing.JFrame;\nimport javax.swing.JLabel;\nimport javax.swing.JPasswordField;\nimport javax.swing.JTextField;\n\npublic class Login {\n\t\n\tpublic static void main(String[] args) {\n\t\t\t\t\t//界面初始化\n\t\t\t\t\t\tJFrame f=new JFrame();\n\t\t\t\tf.setTitle(\"Login\");\n\t\tf.setSize(300, 500);\n\t\t\tf.setDefaultCloseOperation(3);\n\t\tf.setLocationRelativeTo(null);\n\t\t\n\t\tFlowLayout layout=new FlowLayout(FlowLayout.LEFT);\n\t\tf.setLayout(layout);\n\t\t\n\t\tJLabel name=new JLabel(\"账号:\");\n\t\tJTextField txtname=new JTextField();\n\t\ttxtname.setPreferredSize(new Dimension(200, 20));\n\t\t\n\t\tJLabel pass=new JLabel(\"密码:\");\n\t\tJPasswordField txtpass=new JPasswordField();\n\t\ttxtpass.setPreferredSize(new Dimension(200, 20));\n\t\t\n\t\tJButton jb=new JButton(\"登录\");\n\t\t\n\t\tf.add(name);\n\t\tf.add(txtname);\n\t\tf.add(pass);\n\t\tf.add(txtpass);\n\t\tf.add(jb);\n\t\tf.setVisible(true);\n\t\tLoginListener ll=new LoginListener();//实例化事件处理类\n\t\tll.setTxtname(txtname);\n\t\tll.setTxtpass(txtpass);\n\t\tll.setJf(f);\n\t\ttxtname.addKeyListener(ll);//添加键盘监听\n\t\tjb.addActionListener(ll);//添加动作监听\n\t}\n}\n\nimport java.awt.Color;\nimport java.awt.FlowLayout;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\nimport java.awt.event.KeyEvent;\nimport java.awt.event.KeyListener;\nimport javax.swing.JFrame;\nimport javax.swing.JMenu;\nimport javax.swing.JMenuBar;\nimport javax.swing.JMenuItem;\nimport javax.swing.JOptionPane;\nimport javax.swing.JPasswordField;\nimport javax.swing.JTextField;\n//事件处理类,实现ActionListener,KeyListener接口\npublic class LoginListener implements ActionListener,KeyListener{\n\t\n\tprivate JTextField txtname;\n\tprivate JPasswordField txtpass;\n\tprivate JFrame jframe;\n\t\n\tpublic JTextField getTxtname() {\n\t\treturn txtname;\n\t}\n\n\tpublic void setTxtname(JTextField txtname) {\n\t\tthis.txtname = txtname;\n\t}\n\n\tpublic JPasswordField getTxtpass() {\n\t\treturn txtpass;\n\t}\n\n\tpublic void setTxtpass(JPasswordField txtpass) {\n\t\tthis.txtpass = txtpass;\n\t}\n\n\tpublic JFrame getJf() {\n\t\treturn jframe;\n\t}\n\n\tpublic void setJf(JFrame jf) {\n\t\tthis.jframe = jf;\n\t}\n\n\tpublic void keyTyped(KeyEvent e) {\n\t\t\n\t}\n\n\t//重写keyPressed方法\n\tpublic void keyPressed(KeyEvent e) {\n\t\tint code=e.getKeyCode();\n\t\tif (!((code &= 65 && code &= 90) || (code &= 48 && code &= 57)|| code==16)) {\n\t\t\tJOptionPane.showMessageDialog(jframe, \"输入错误请重新输入。\");\n\t\t}\n\t}\n\n\tpublic void keyReleased(KeyEvent e) {\n\t\t\n\t}\n\n\t//重写actionPerformed\n\tpublic void actionPerformed(ActionEvent e) {\n\t\tif(\"admin\".equals(txtname.getText())&& \"123456\".equals(txtpass.getText())){\n\t\t\tjframe.dispose();\n\t\t\tJFrame jf=new JFrame(\"画图\");\n\t\t\tjf.setSize(500, 500);\n\t\t\tjf.setDefaultCloseOperation(3);\n\t\t\tjf.setLocationRelativeTo(null);\n\t\t\tFlowLayout layout=new FlowLayout(FlowLayout.LEFT);\n\t\t\tjf.setLayout(layout);\n\t\t\tJMenuBar JB=new JMenuBar();\n\t\t\tJMenu file=new JMenu(\"文件\");\n\t\t\tJMenuItem f_new=new JMenuItem(\"新建\");\n\t\t\tJMenuItem f_close=new JMenuItem(\"关闭\");\n\t\t\tfile.add(f_new);\n\t\t\tfile.add(f_close);\n\t\t\tJB.add(file);\n\t\t\tjf.add(JB);\n\t\t\tjf.setVisible(true);\t\t\t\n\t\t}else{\n\t\t\tJOptionPane.showMessageDialog(jframe, \"输入的账号或密码错误,请重新输入!\");\n\t\t}\n\t}\n}\n","updated":"T14:30:17.000Z","canComment":false,"commentPermission":"anyone","commentCount":0,"collapsedCount":0,"likeCount":0,"state":"published","isLiked":false,"slug":"","isTitleImageFullScreen":false,"rating":"none","titleImage":"","links":{"comments":"/api/posts//comments"},"reviewers":[],"topics":[{"url":"/topic/","id":"","name":"Java"}],"adminClosedComment":false,"titleImageSize":{"width":0,"height":0},"href":"/api/posts/","excerptTitle":"","tipjarState":"inactivated","annotationAction":[],"sourceUrl":"","pageCommentsCount":0,"hasPublishingDraft":false,"snapshotUrl":"","publishedTime":"T22:30:17+08:00","url":"/p/","lastestLikers":[],"summary":"接口是Java中的一个重要的概念,很多的时候我们定义一个方法的时候可能并没有想到这个方法应该如何去实现,而是只是想到有这样的方法。实际上接口的作用是定义一个规范,规范了实现这个接口的类都应该具有怎么样的方法。我们可以想象生活中这样的例子:工厂…","reviewingCommentsCount":0,"meta":{"previous":null,"next":null},"annotationDetail":null,"commentsCount":0,"likesCount":0,"FULLINFO":true}},"User":{"bu-ding-10-95":{"isFollowed":false,"name":"布丁","headline":"","avatarUrl":"/8c859ee6c6a3e1f4567ed_s.jpg","isFollowing":false,"type":"people","slug":"bu-ding-10-95","bio":"Coding maybe","hash":"9a42c92c02df","uid":681000,"isOrg":false,"description":"","profileUrl":"/people/bu-ding-10-95","avatar":{"id":"8c859ee6c6a3e1f4567ed","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false,"badge":{"identity":null,"bestAnswerer":null}}},"Comment":{},"favlists":{}},"me":{},"global":{},"columns":{"next":{}},"columnPosts":{},"columnSettings":{"colomnAuthor":[],"uploadAvatarDetails":"","contributeRequests":[],"contributeRequestsTotalCount":0,"inviteAuthor":""},"postComments":{},"postReviewComments":{"comments":[],"newComments":[],"hasMore":true},"favlistsByUser":{},"favlistRelations":{},"promotions":{},"switches":{"couldAddVideo":false},"draft":{"titleImage":"","titleImageSize":{},"isTitleImageFullScreen":false,"canTitleImageFullScreen":false,"title":"","titleImageUploading":false,"error":"","content":"","draftLoading":false,"globalLoading":false,"pendingVideo":{"resource":null,"error":null}},"drafts":{"draftsList":[],"next":{}},"config":{"userNotBindPhoneTipString":{}},"recommendPosts":{"articleRecommendations":[],"columnRecommendations":[]},"env":{"isAppView":false,"appViewConfig":{"content_padding_top":128,"content_padding_bottom":56,"content_padding_left":16,"content_padding_right":16,"title_font_size":22,"body_font_size":16,"is_dark_theme":false,"can_auto_load_image":true,"app_info":"OS=iOS"},"isApp":false},"sys":{}}java中如何初始化接口
chart.setBackgroundImageAlpha(Paint.OPAQUE);
其中,Paint类型可以直接用Color类。
其中Paint就是一个接口,只能通过Paint直接调用其中的参数。
public interface RandVals {
int rint = (int)(Math.random() * 10);
long rlong = (long)(Math.random() * 10);
float rfloat = (float)(Math.random() * 10);
double rdouble = Math.random() * 10;
由于字段是static的,所以它们会在首次装载类之后、以及首次访问任何字段之前获得初始化。下面是一个简单的测试:
//: TestRandVals.java
public class TestRandVals {
public static void main(String[] args) {
System.out.println(RandVals.rint);
System.out.println(RandVals.rlong);
System.out.println(RandVals.rfloat);
System.out.println(RandVals.rdouble);
Copyright (C) , All Rights Reserved.
版权所有 闽ICP备号
processed in 0.036 (s). 13 q(s)3776人阅读
Java语言编程(2)
一、Java接口的基本内容
[1].Java编程语言中不支持多重继承(即Java中一个类不能有多于一个的直接父类),但可以实现多个接口,这就间接地实现了多重继承。
[2].接口(Interface)将产生一个完全抽象的类,它是用来建立类与类之间的协议的,其内部只提供调用方法的形式(创建者确定方法名、参数列表及返回类型),而没有提供任何具体的方法体。具体的实现方法(该接口中的所有方法)需要在遵循该特定接口的类中进行实现。创建接口需要使用关键字interface,而创建一个遵循某接口的类则需要使用关键字implements。
二、Java接口的基本特征
&&& [1].接口可以包含域,但是这些域不是接口的一部分,它们的值被存储在该接口的静态存储区内;域隐式为public、static、final的(域名通常大写且单词之间以下划线连接),域不能是&空final&,在使用之前必须显式地初始化,但可以被非常量表达式初始化。
&&& [2].当实现一个接口时,接口中的方法必须是public的,通常隐式地为public及abstract的。
&&& [3].接口必须通过类来实现它的抽象方法,且该类必须实现该接口中的所有方法,否则该类仍是一个抽象类。
&&& [4].接口因为没有构造器而不能进行实例化,但运行定义接口类型的引用变量,该引用变量实现了该接口的类的实例。比如:
&&& Interface Base{/*&*/}
&&& Public class Derived implements Base{/*&*/}
&&& //! Base b=new Base();error:接口不能进行实例化
&&& Base b=new Derived();//引用变量b被定义为类型Base,引用了Derived实例
&&& [5].一个类只能继承一个父类,但可以实现多个接口,并可以向上转型为每个接口(因为每个接口都是一个独立的类型)。按照先类后接口(多个接口以逗号分开)的顺序进行实现。例如:
Class BaseClass{}
& & Interface BaseIntfaceA{}
& & Interface BaseIntfaceB{}
& & Public class Derived extends BaseClass
implements BaseIntfaceA, BaseIntfaceB{}
&&& [6].接口可以嵌套,嵌套在接口中的接口自动为public而不能修改为private。当实现某个接口时,不需要实现嵌套在其内部的任何接口。类中的private接口不能在定义它的类之外被实现。
&&& [7].接口可以很好地应用于松耦合软件系统构建之中。通过接口可以很方便地对已经存在的系统进行自下而上的抽象,对于任意的两个类,只要他们存在有相同的功能,就能从中抽象出一个接口类型,而不用理会它们是否源自同一个父类。对于两个系统,通过接口交互可以获得比抽象类交互更好的松耦合特性。
三、接口与抽象类的异同点
&&& [1].相同点:
&1&.二者都包含有描述系统能提供服务的抽象方法,都不提具体实现的方法体,都不能被实例化。
&2&.都位于继承树的上层,都代表系统的抽象层。当系统使用继承树上的类时,应尽量把引用变量声明为继承树的上层抽象类型,这样可以提高两个系统的松耦合程度。
&&& [2].不同点:
&1&.抽象类中可以定义调用方法的方法体以免在子类中的重复定义,对子类中修改方法体不会造成影响;对于接口,一旦接口公布就必须保持稳定,因为随意向接口中添加方法会直接影响到子类的功能,此时子类要么实现新增的方法,要么就声明为抽象类,而声明为抽象类就意味着该类不能进行实例化,也就限制了该类的应用了。
&2&.一个类只能有一个直接父类(此父类可以是抽象类),但它可以实现多个接口。当子类覆盖父类的调用方法或隐藏父类的成员变量及静态方法时,Java虚拟机采用不同的绑定机制,为了简化系统设计的复杂性和绑定机制,Java禁止多重继承;对于接口,其内部只含有抽象方法而没有实例变量及静态方法,即便一个类实现多个接口也不会增加绑定机制的复杂性。
四、接口和抽象类的使用原则
&&& [1].使用接口作为系统与外界交互的窗口。
&&& [2].接口必须保持稳定性。
&&& [3].使用抽象类来定制系统中扩展点。
Reference:
Bruce Eckel. &&Thinking in Java&&4-th Edition
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:65516次
排名:千里之外
原创:16篇
评论:13条
(1)(1)(7)(1)(1)(5)
(window.slotbydup = window.slotbydup || []).push({
id: '4740881',
container: s,
size: '200,200',
display: 'inlay-fix'登录以解锁更多InfoQ新功能
获取更新并接收通知
给您喜爱的内容点赞
关注您喜爱的编辑与同行
966,690 八月 独立访问用户
语言 & 开发
架构 & 设计
文化 & 方法
您目前处于:
Java深度历险(二)——Java类的加载、链接和初始化
Java深度历险(二)——Java类的加载、链接和初始化
10&他的粉丝
日. 估计阅读时间:
硅谷人工智能、机器学习、互联网金融、未来移动技术架构 ,
相关厂商内容
相关赞助商
一般的类加载器在尝试自己去加载某个Java类之前,会首先代理给其父类加载器。当父类加载器找不到的时候,才会尝试自己加载。这个逻辑是封装在java.lang.ClassLoader类的方法中的。一般来说,父类优先的策略就足够好了。在某些情况下,可能需要采取相反的策略,即先尝试自己加载,找不到的时候再代理给父类加载器。这种做法在Java的Web容器中比较常见,也是推荐的做法。比如,为每个Web应用都提供一个独立的类加载器,使用的就是自己优先加载的策略。则允许Web应用选择类加载器使用的策略。
类加载器的一个重要用途是在JVM中为相同名称的Java类创建隔离空间。在JVM中,判断两个类是否相同,不仅是根据该类的,还需要根据两个类的定义类加载器。只有两者完全一样,才认为两个类的是相同的。因此,即便是同样的Java字节代码,被两个不同的类加载器定义之后,所得到的Java类也是不同的。如果试图在两个类的对象之间进行赋值操作,会抛出。这个特性为同样名称的Java类在JVM中共存创造了条件。在实际的应用中,可能会要求同一名称的Java类的不同版本在JVM中可以同时存在。通过类加载器就可以满足这种需求。这种技术在中得到了广泛的应用。
Java类的链接
Java类的链接指的是将Java类的二进制代码合并到JVM的运行状态之中的过程。在链接之前,这个类必须被成功加载。类的链接包括验证、准备和解析等几个步骤。验证是用来确保Java类的二进制表示在结构上是完全正确的。如果验证过程出现错误的话,会抛出错误。准备过程则是创建Java类中的静态域,并将这些域的值设为默认值。准备过程并不会执行代码。在一个Java类中会包含对其它类或接口的形式引用,包括它的父类、所实现的接口、方法的形式参数和返回值的Java类等。解析的过程就是确保这些被引用的类能被正确的找到。解析的过程可能会导致其它的Java类被加载。
不同的JVM实现可能选择不同的解析策略。一种做法是在链接的时候,就递归的把所有依赖的形式引用都进行解析。而另外的做法则可能是只在一个形式引用真正需要的时候才进行解析。也就是说如果一个Java类只是被引用了,但是并没有被真正用到,那么这个类有可能就不会被解析。考虑下面的代码:
public class LinkTest {
public static void main(String[] args) {
ToBeLinked toBeLinked =
System.out.println(&Test link.&);
类 LinkTest引用了类ToBeLinked,但是并没有真正使用它,只是声明了一个变量,并没有创建该类的实例或是访问其中的静态域。在 Oracle的JDK 6中,如果把编译好的ToBeLinked的Java字节代码删除之后,再运行LinkTest,程序不会抛出错误。这是因为ToBeLinked类没有被真正用到,而Oracle的JDK 6所采用的链接策略使得ToBeLinked类不会被加载,因此也不会发现ToBeLinked的Java字节代码实际上是不存在的。如果把代码改成ToBeLinked toBeLinked = new ToBeLinked();之后,再按照相同的方法运行,就会抛出异常了。因为这个时候ToBeLinked这个类被真正使用到了,会需要加载这个类。
Java类的初始化
当一个Java类第一次被真正使用到的时候,JVM会进行该类的初始化操作。初始化过程的主要操作是执行静态代码块和初始化静态域。在一个类被初始化之前,它的直接父类也需要被初始化。但是,一个接口的初始化,不会引起其父接口的初始化。在初始化的时候,会按照源代码中从上到下的顺序依次执行静态代码块和初始化静态域。考虑下面的代码:
public class StaticTest {
public static int X = 10;
public static void main(String[] args) {
System.out.println(Y); //输出60
public static int Y = X * 2;
在上面的代码中,在初始化的时候,静态域的初始化和静态代码块的执行会从上到下依次执行。因此变量X的值首先初始化成10,后来又被赋值成30;而变量Y的值则被初始化成60。
Java类和接口的初始化只有在特定的时机才会发生,这些时机包括:
创建一个Java类的实例。如
MyClass obj = new MyClass()
调用一个Java类中的静态方法。如
MyClass.sayHello()
给Java类或接口中声明的静态域赋值。如
MyClass.value = 10
访问Java类或接口中声明的静态域,并且该域不是常值变量。如
int value = MyClass.value
在顶层Java类中执行assert语句。
通过Java反射API也可能造成类和接口的初始化。需要注意的是,当访问一个Java类或接口中的静态域的时候,只有真正声明这个域的类或接口才会被初始化。考虑下面的代码:
static int value = 100;
System.out.println(&Class B is initialized.&); //输出
class A extends B {
System.out.println(&Class A is initialized.&); //不会输出
public class InitTest {
public static void main(String[] args) {
System.out.println(A.value); //输出100
在上述代码中,类InitTest通过A.value引用了类B中声明的静态域value。由于value是在类B中声明的,只有类B会被初始化,而类A则不会被初始化。
创建自己的类加载器
在 Java应用开发过程中,可能会需要创建应用自己的类加载器。典型的场景包括实现特定的Java字节代码查找方式、对字节代码进行加密/解密以及实现同名 Java类的隔离等。创建自己的类加载器并不是一件复杂的事情,只需要继承自java.lang.ClassLoader类并覆写对应的方法即可。 java.lang.ClassLoader中提供的方法有不少,下面介绍几个创建类加载器时需要考虑的:
:这个方法用来完成从Java字节代码的字节数组到java.lang.Class的转换。这个方法是不能被覆写的,一般是用原生代码来实现的。
:这个方法用来根据名称查找已经加载过的Java类。一个类加载器不会重复加载同一名称的类。
:这个方法用来根据名称查找并加载Java类。
:这个方法用来根据名称加载Java类。
:这个方法用来链接一个Java类。
这里比较 容易混淆的是findClass()方法和loadClass()方法的作用。前面提到过,在Java类的链接过程中,会需要对Java类进行解析,而解析可能会导致当前Java类所引用的其它Java类被加载。在这个时候,JVM就是通过调用当前类的定义类加载器的loadClass()方法来加载其它类的。findClass()方法则是应用创建的类加载器的扩展点。应用自己的类加载器应该覆写findClass()方法来添加自定义的类加载逻辑。 loadClass()方法的默认实现会负责调用findClass()方法。
前面提到,类加载器的代理模式默认使用的是父类优先的策略。这个策略的实现是封装在loadClass()方法中的。如果希望修改此策略,就需要覆写loadClass()方法。
下面的代码给出了自定义的类加载的常见实现模式:
public class MyClassLoader extends ClassLoader {
protected Class&?& findClass(String name) throws ClassNotFoundException {
byte[] b = //查找或生成Java类的字节代码
return defineClass(name, b, 0, b.length);
Java语言规范(第三版)- 第十三章:
JVM规范(第二版) - 第五章:
感谢对本文的审校。
给InfoQ中文站投稿或者参与内容翻译工作,请邮件至。也欢迎大家加入到中与我们的编辑和其他读者朋友交流。
Author Contacted
语言 & 开发
23 他的粉丝
架构 & 设计
144 他的粉丝
文化 & 方法
13 他的粉丝
Java深度历险
8 他的粉丝
1 他的粉丝
0 他的粉丝
0 他的粉丝
1 他的粉丝
195 他的粉丝
2 他的粉丝
8 他的粉丝
1 他的粉丝
告诉我们您的想法
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
确实很深啊
好文给力!
讲的太清楚啦
能否应用到什么场景
理清了从byte[]到Class对象及初始化
只有真正声明这个域的类或接口才会被初始化
Re: 错误不少
Re: 错误不少
关于类初始化时机的疑似错误
Re: 关于类初始化时机的疑似错误
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
赞助商链接
InfoQ每周精要
订阅InfoQ每周精要,加入拥有25万多名资深开发者的庞大技术社区。
架构 & 设计
文化 & 方法
<及所有内容,版权所有 &#169;
C4Media Inc.
服务器由 提供, 我们最信赖的ISP伙伴。
北京创新网媒广告有限公司
京ICP备号-7
找回密码....
InfoQ账号使用的E-mail
关注你最喜爱的话题和作者
快速浏览网站内你所感兴趣话题的精选内容。
内容自由定制
选择想要阅读的主题和喜爱的作者定制自己的新闻源。
设置通知机制以获取内容更新对您而言是否重要
注意:如果要修改您的邮箱,我们将会发送确认邮件到您原来的邮箱。
使用现有的公司名称
修改公司名称为:
公司性质:
使用现有的公司性质
修改公司性质为:
使用现有的公司规模
修改公司规模为:
使用现在的国家
使用现在的省份
Subscribe to our newsletter?
Subscribe to our industry email notices?
我们发现您在使用ad blocker。
我们理解您使用ad blocker的初衷,但为了保证InfoQ能够继续以免费方式为您服务,我们需要您的支持。InfoQ绝不会在未经您许可的情况下将您的数据提供给第三方。我们仅将其用于向读者发送相关广告内容。请您将InfoQ添加至白名单,感谢您的理解与支持。

我要回帖

更多关于 java 初始化 的文章

 

随机推荐