本系列文章將整理到我在GitHub上的《Java面試指南》倉(cāng)庫(kù),更多精彩內(nèi)容請(qǐng)到我的倉(cāng)庫(kù)里查看
成都創(chuàng)新互聯(lián)企業(yè)建站,10年網(wǎng)站建設(shè)經(jīng)驗(yàn),專注于網(wǎng)站建設(shè)技術(shù),精于網(wǎng)頁(yè)設(shè)計(jì),有多年建站和網(wǎng)站代運(yùn)營(yíng)經(jīng)驗(yàn),設(shè)計(jì)師為客戶打造網(wǎng)絡(luò)企業(yè)風(fēng)格,提供周到的建站售前咨詢和貼心的售后服務(wù)。對(duì)于成都做網(wǎng)站、成都網(wǎng)站制作中不同領(lǐng)域進(jìn)行深入了解和探索,創(chuàng)新互聯(lián)在網(wǎng)站建設(shè)中充分了解客戶行業(yè)的需求,以靈動(dòng)的思維在網(wǎng)頁(yè)中充分展現(xiàn),通過(guò)對(duì)客戶行業(yè)精準(zhǔn)市場(chǎng)調(diào)研,為客戶提供的解決方案。
https://github.com/h3pl/Java-Tutorial
喜歡的話麻煩點(diǎn)下Star哈
文章首發(fā)于我的個(gè)人博客:
www.how2playlife.com
IDE是把雙刃劍,它可以什么都幫你做了,你只要敲幾行代碼,點(diǎn)幾下鼠標(biāo),程序就跑起來(lái)了,用起來(lái)相當(dāng)方便。你不用去關(guān)心它后面做了些什么,執(zhí)行了哪些命令,基于什么原理。然而也是這種過(guò)分的依賴往往讓人散失了最基本的技能,當(dāng)?shù)搅艘粋€(gè)沒(méi)有IDE的地方,你便覺(jué)得無(wú)從下手,給你個(gè)代碼都不知道怎么去跑。好比給你瓶水,你不知道怎么打開(kāi)去喝,然后活活給渴死。之前用慣了idea,Java文件編譯運(yùn)行的命令基本忘得一干二凈。
IDE是把雙刃劍,它可以什么都幫你做了,你只要敲幾行代碼,點(diǎn)幾下鼠標(biāo),程序就跑起來(lái)了,用起來(lái)相當(dāng)方便。
你不用去關(guān)心它后面做了些什么,執(zhí)行了哪些命令,基于什么原理。然而也是這種過(guò)分的依賴往往讓人散失了最基本的技能,當(dāng)?shù)搅艘粋€(gè)沒(méi)有IDE的地方,你便覺(jué)得無(wú)從下手,給你個(gè)代碼都不知道怎么去跑。好比給你瓶水,你不知道怎么打開(kāi)去喝,然后活活給渴死。
之前用慣了idea,Java文件編譯運(yùn)行的命令基本忘得一干二凈。
那好,不如咱們先來(lái)了解一下IDE的實(shí)現(xiàn)原理,這樣一來(lái),即使離開(kāi)IDE,我們還是知道如何運(yùn)行Java程序了。
像Eclipse等java IDE是怎么編譯和查找java源代碼的呢?
這個(gè)無(wú)需多說(shuō),在編譯器寫入代碼,并保存到文件。這個(gè)利用流來(lái)實(shí)現(xiàn)。
java提供了JavaCompiler,我們可以通過(guò)它來(lái)編譯java源文件為class文件。
可以通過(guò)Class.forName(fullClassPath)或自定義類加載器來(lái)實(shí)現(xiàn)。
通過(guò)上面一個(gè)查找class,得到Class對(duì)象后,可以通過(guò)newInstance()或構(gòu)造器的newInstance()得到對(duì)象。然后得到Method,最后調(diào)用方法,傳入相關(guān)參數(shù)即可。
示例代碼:
public class MyIDE { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { // 定義java代碼,并保存到文件(Test.java) StringBuilder sb = new StringBuilder(); sb.append("package com.tommy.core.test.reflect;\n"); sb.append("public class Test {\n"); sb.append(" private String name;\n"); sb.append(" public Test(String name){\n"); sb.append(" this.name = name;\n"); sb.append(" System.out.println(\"hello,my name is \" + name);\n"); sb.append(" }\n"); sb.append(" public String sayHello(String name) {\n"); sb.append(" return \"hello,\" + name;\n"); sb.append(" }\n"); sb.append("}\n"); System.out.println(sb.toString()); String baseOutputDir = "F:\\output\\classes\\"; String baseDir = baseOutputDir + "com\\tommy\\core\\test\\reflect\\"; String targetJavaOutputPath = baseDir + "Test.java"; // 保存為java文件 FileWriter fileWriter = new FileWriter(targetJavaOutputPath); fileWriter.write(sb.toString()); fileWriter.flush(); fileWriter.close(); // 編譯為class文件 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager manager = compiler.getStandardFileManager(null,null,null); List<File> files = new ArrayList<>(); files.add(new File(targetJavaOutputPath)); Iterable compilationUnits = manager.getJavaFileObjectsFromFiles(files); // 編譯 // 設(shè)置編譯選項(xiàng),配置class文件輸出路徑 Iterable<String> options = Arrays.asList("-d",baseOutputDir); JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, options, null, compilationUnits); // 執(zhí)行編譯任務(wù) task.call(); // 通過(guò)反射得到對(duì)象 // Class clazz = Class.forName("com.tommy.core.test.reflect.Test"); // 使用自定義的類加載器加載class Class clazz = new MyClassLoader(baseOutputDir).loadClass("com.tommy.core.test.reflect.Test"); // 得到構(gòu)造器 Constructor constructor = clazz.getConstructor(String.class); // 通過(guò)構(gòu)造器new一個(gè)對(duì)象 Object test = constructor.newInstance("jack.tsing"); // 得到sayHello方法 Method method = clazz.getMethod("sayHello", String.class); // 調(diào)用sayHello方法 String result = (String) method.invoke(test, "jack.ma"); System.out.println(result); } }
自定義類加載器代碼:
public class MyClassLoader extends ClassLoader { private String baseDir; public MyClassLoader(String baseDir) { this.baseDir = baseDir; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { String fullClassFilePath = this.baseDir + name.replace("\\.","/") + ".class"; File classFilePath = new File(fullClassFilePath); if (classFilePath.exists()) { FileInputStream fileInputStream = null; ByteArrayOutputStream byteArrayOutputStream = null; try { fileInputStream = new FileInputStream(classFilePath); byte[] data = new byte[1024]; int len = -1; byteArrayOutputStream = new ByteArrayOutputStream(); while ((len = fileInputStream.read(data)) != -1) { byteArrayOutputStream.write(data,0,len); } return defineClass(name,byteArrayOutputStream.toByteArray(),0,byteArrayOutputStream.size()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (null != fileInputStream) { try { fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (null != byteArrayOutputStream) { try { byteArrayOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } return super.findClass(name); } }
注:以下紅色標(biāo)記的參數(shù)在下文中有所講解。
本部分參考 https://www.cnblogs.com/xiazdong/p/3216220.html
用法: javac 其中, 可能的選項(xiàng)包括:-g 生成所有調(diào)試信息-g:none 不生成任何調(diào)試信息-g:{lines,vars,source} 只生成某些調(diào)試信息-nowarn 不生成任何警告-verbose 輸出有關(guān)編譯器正在執(zhí)行的操作的消息-deprecation 輸出使用已過(guò)時(shí)的 API 的源位置-classpath <路徑> 指定查找用戶類文件和注釋處理程序的位置-cp <路徑> 指定查找用戶類文件和注釋處理程序的位置-sourcepath <路徑> 指定查找輸入源文件的位置-bootclasspath <路徑> 覆蓋引導(dǎo)類文件的位置-extdirs <目錄> 覆蓋所安裝擴(kuò)展的位置-endorseddirs <目錄> 覆蓋簽名的標(biāo)準(zhǔn)路徑的位置-proc:{none,only} 控制是否執(zhí)行注釋處理和/或編譯。-processor [, , …] 要運(yùn)行的注釋處理程序的名稱; 繞過(guò)默認(rèn)的搜索進(jìn)程 -processorpath <路徑> 指定查找注釋處理程序的位置-d <目錄> 指定放置生成的類文件的位置-s <目錄> 指定放置生成的源文件的位置-implicit:{none,class} 指定是否為隱式引用文件生成類文件-encoding <編碼> 指定源文件使用的字符編碼-source <發(fā)行版> 提供與指定發(fā)行版的源兼容性-target <發(fā)行版> 生成特定 VM 版本的類文件-version 版本信息-help 輸出標(biāo)準(zhǔn)選項(xiàng)的提要-A關(guān)鍵字[=值] 傳遞給注釋處理程序的選項(xiàng)-X 輸出非標(biāo)準(zhǔn)選項(xiàng)的提要-J<標(biāo)記> 直接將 <標(biāo)記> 傳遞給運(yùn)行時(shí)系統(tǒng)-Werror 出現(xiàn)警告時(shí)終止編譯@<文件名> 從文件讀取選項(xiàng)和文件名在詳細(xì)介紹javac命令之前,先看看這個(gè)classpath是什么 classpath是什么在dos下編譯java程序,就要用到classpath這個(gè)概念,尤其是在沒(méi)有設(shè)置環(huán)境變量的時(shí)候。classpath就是存放.class等編譯后文件的路徑。javac:如果當(dāng)前你要編譯的java文件中引用了其它的類(比如說(shuō):繼承),但該引用類的.class文件不在當(dāng)前目錄下,這種情況下就需要在javac命令后面加上-classpath參數(shù),通過(guò)使用以下三種類型的方法 來(lái)指導(dǎo)編譯器在編譯的時(shí)候去指定的路徑下查找引用類。(1).絕對(duì)路徑:javac -classpath c:/junit3.8.1/junit.jar Xxx.java(2).相對(duì)路徑:javac -classpath ../junit3.8.1/Junit.javr Xxx.java(3).系統(tǒng)變量:javac -classpath %CLASSPATH% Xxx.java (注意:%CLASSPATH%表示使用系統(tǒng)變量CLASSPATH的值進(jìn)行查找,這里假設(shè)Junit.jar的路徑就包含在CLASSPATH系統(tǒng)變量中) IDE中的classpath對(duì)于一個(gè)普通的Javaweb項(xiàng)目,一般有這樣的配置:1 WEB-INF/classes,lib才是classpath,WEB-INF/ 是資源目錄, 客戶端不能直接訪問(wèn)。2、WEB-INF/classes目錄存放src目錄java文件編譯之后的class文件,xml、properties等資源配置文件,這是一個(gè)定位資源的入口。3、引用classpath路徑下的文件,只需在文件名前加classpath:classpath:applicationContext-*.xml classpath:context/conf/controller.xml4、lib和classes同屬classpath,兩者的訪問(wèn)優(yōu)先級(jí)為: lib>classes。5、classpath 和 classpath* 區(qū)別:classpath:只會(huì)到你的class路徑中查找找文件; classpath*:不僅包含class路徑,還包括jar文件中(class路徑)進(jìn)行查找。 總結(jié):(1).何時(shí)需要使用-classpath:當(dāng)你要編譯或執(zhí)行的類引用了其它的類,但被引用類的.class文件不在當(dāng)前目錄下時(shí),就需要通過(guò)-classpath來(lái)引入類(2).何時(shí)需要指定路徑:當(dāng)你要編譯的類所在的目錄和你執(zhí)行javac命令的目錄不是同一個(gè)目錄時(shí),就需要指定源文件的路徑(CLASSPATH是用來(lái)指定.class路徑的,不是用來(lái)指定.java文件的路徑的) Java項(xiàng)目和Java web項(xiàng)目的本質(zhì)區(qū)別(看清IDE及classpath本質(zhì))現(xiàn)在只是說(shuō)說(shuō)Java Project和Web Project,那么二者有區(qū)別么?回答:沒(méi)有!都是Java語(yǔ)言的應(yīng)用,只是應(yīng)用場(chǎng)合不同罷了,那么他們的本質(zhì)到底是什么?回答:編譯后路徑!虛擬機(jī)執(zhí)行的是class文件而不是java文件,那么我們不管是何種項(xiàng)目都是寫的java文件,怎么就不一樣了呢?分成java和web兩種了呢?從.classpath入手來(lái)看,這個(gè)文件在每個(gè)項(xiàng)目目錄下都是存在的,很少有人打開(kāi)看吧,那么我們就來(lái)一起看吧。這是一個(gè)XML文件,使用文本編輯器打開(kāi)即可。這里展示一個(gè)web項(xiàng)目的.classpathXml代碼 <?xml version="1.0" encoding="UTF-8"?> <classpath> <classpathentry kind="src" path="src"/> <classpathentry kind="src" path="resources"/> <classpathentry kind="src" path="test"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="lib" path="lib/servlet-api.jar"/> <classpathentry kind="lib" path="webapp/WEB-INF/lib/struts2-core-2.1.8.1.jar"/> …… <classpathentry kind="output" path="webapp/WEB-INF/classes"/> </classpath> XML文檔包含一個(gè)根元素,就是classpath,類路徑,那么這里面包含了什么信息呢?子元素是classpathentry,kind屬性區(qū)別了種 類信息,src源碼,con你看看后面的path就知道是JRE容器的信息。lib是項(xiàng)目依賴的第三方類庫(kù),output是src編譯后的位置。既然是web項(xiàng)目,那么就是WEB-INF/classes目錄,可能用MyEclipse的同學(xué)會(huì)說(shuō)他們那里是WebRoot或者是WebContext而不是webapp,有區(qū)別么?回答:完全沒(méi)有!既然看到了編譯路徑的本來(lái)面目后,還區(qū)分什么java項(xiàng)目和web項(xiàng)目么?回答:不區(qū)分!普通的java 項(xiàng)目你這樣寫就行了: ,看看Eclipse是不是這樣生成的?這個(gè)問(wèn)題解決了吧。 再說(shuō)說(shuō)webapp目錄命名的問(wèn)題,這個(gè)無(wú)所謂啊,web項(xiàng)目是要發(fā)布到服務(wù)器上的對(duì)吧,那么服務(wù)器讀取的是類文件和頁(yè)面文件吧,它不管源文件,它也無(wú)法去理解源文件。那么webapp目錄的命名有何關(guān)系呢?只要讓服務(wù)器找到不就行了。 -g、-g:none、-g:{lines,vars,source}?-g:在生成的class文件中包含所有調(diào)試信息(行號(hào)、變量、源文件) ?-g:none :在生成的class文件中不包含任何調(diào)試信息。這個(gè)參數(shù)在javac編譯中是看不到什么作用的,因?yàn)檎{(diào)試信息都在class文件中,而我們看不懂這個(gè)class文件。為了看出這個(gè)參數(shù)的作用,我們?cè)趀clipse中進(jìn)行實(shí)驗(yàn)。在eclipse中,我們經(jīng)常做的事就是“debug”,而在debug的時(shí)候,我們會(huì) ?加入“斷點(diǎn)”,這個(gè)是靠-g:lines起作用,如果不記錄行號(hào),則不能加斷點(diǎn)。 ?在“variables”窗口中查看當(dāng)前的變量,如下圖所示,這是靠-g:vars起作用,否則不能查看變量信息。 ?在多個(gè)文件之間來(lái)回調(diào)用,比如 A.java的main()方法中調(diào)用了B.java的fun()函數(shù),而我想看看程序進(jìn)入fun()后的狀態(tài),這是靠-g:source,如果沒(méi)有這個(gè)參數(shù),則不能查看B.java的源代碼。 -bootclasspath、-extdirs-bootclasspath和-extdirs 幾乎不需要用的,因?yàn)樗怯脕?lái)改變 “引導(dǎo)類”和“擴(kuò)展類”。 ?引導(dǎo)類(組成Java平臺(tái)的類):Java\jdk1.7.0_25\jre\lib\rt.jar等,用-bootclasspath設(shè)置。 ?擴(kuò)展類:Java\jdk1.7.0_25\jre\lib\ext目錄中的文件,用-extdirs設(shè)置。 ?用戶自定義類:用-classpath設(shè)置。我們用-verbose編譯后出現(xiàn)的“類文件的搜索路徑”,就是由上面三個(gè)路徑組成,如下: [類文件的搜索路徑: C:\Java\jdk1.7.0_25\jre\lib\resources.jar,C:\Java\jdk1.7.0_25 \jre\lib\rt.jar,C:\Java\jdk1.7.0_25\jre\lib\sunrsasign.jar,C:\Java\jdk1.7.0_25\j re\lib\jsse.jar,C:\Java\jdk1.7.0_25\jre\lib\jce.jar,C:\Java\jdk1.7.0_25\jre\lib\ charsets.jar,C:\Java\jdk1.7.0_25\jre\lib\jfr.jar,C:\Java\jdk1.7.0_25\jre\classes ,C:\Java\jdk1.7.0_25\jre\lib\ext\access-bridge-32.jar,C:\Java\jdk1.7.0_25\jre\li b\ext\DNSns.jar,C:\Java\jdk1.7.0_25\jre\lib\ext\jaccess.jar,C:\Java\jdk1.7.0_25\ jre\lib\ext\localedata.jar,C:\Java\jdk1.7.0_25\jre\lib\ext\sunec.jar,C:\Java\jdk 1.7.0_25\jre\lib\ext\sunjce_provider.jar,C:\Java\jdk1.7.0_25\jre\lib\ext\sunmsca pi.jar,C:\Java\jdk1.7.0_25\jre\lib\ext\sunpkcs11.jar,C:\Java\jdk1.7.0_25\jre\lib \ext\zipfs.jar,..\bin] 如果利用 -bootclasspath 重新定義: javac -bootclasspath src Xxx.java,則會(huì)出現(xiàn)下面錯(cuò)誤:致命錯(cuò)誤: 在類路徑或引導(dǎo)類路徑中找不到程序包 java.lang -sourcepath和-classpath(-cp)?-classpath(-cp)指定你依賴的類的class文件的查找位置。在Linux中,用“:”分隔classpath,而在windows中,用“;”分隔。 ?-sourcepath指定你依賴的類的java文件的查找位置。舉個(gè)例子, public class A { public static void main(String[] args) { B b = new B(); b.print(); } } public class B { public void print() { System.out.println("old"); } } 目錄結(jié)構(gòu)如下:sourcepath //此處為當(dāng)前目錄 |-src |-com |- B.java |- A.java |-bin |- B.class //是 B.java 編譯后的類文件如果要編譯 A.java,則必須要讓編譯器找到類B的位置,你可以指定B.class的位置,也可以是B.java的位置,也可以同時(shí)都存在。 javac -classpath bin src/A.java //查找到B.class javac -sourcepath src/com src/A.java //查找到B.java javac -sourcepath src/com -classpath bin src/A.java //同時(shí)查找到B.class和B.java 如果同時(shí)找到了B.class和B.java,則: ?如果B.class和B.java內(nèi)容一致,則遵循B.class。 ?如果B.class和B.java內(nèi)容不一致,則遵循B.java,并編譯B.java。以上規(guī)則可以通過(guò) -verbose選項(xiàng)看出。 -d?d就是 destination,用于指定.class文件的生成目錄,在eclipse中,源文件都在src中,編譯的class文件都是在bin目錄中。這里我用來(lái)實(shí)現(xiàn)一下這個(gè)功能,假設(shè)項(xiàng)目名稱為project,此目錄為當(dāng)前目錄,且在src/com目錄中有一個(gè)Main.java文件?!?/p> package com; public class Main { public static void main(String[] args) { System.out.println("Hello"); } } javac -d bin src/com/Main.java 上面的語(yǔ)句將Main.class生成在bin/com目錄下。 -implicit:{none,class}?如果有文件為A.java(其中有類A),且在類A中使用了類B,類B在B.java中,則編譯A.java時(shí),默認(rèn)會(huì)自動(dòng)編譯B.java,且生成B.class。 ?implicit:none:不自動(dòng)生成隱式引用的類文件。 ?implicit:class(默認(rèn)):自動(dòng)生成隱式引用的類文件。 public class A { public static void main(String[] args) { B b = new B(); } } public class B { } 如果使用: javac -implicit:none A.java 則不會(huì)生成 B.class。 -source和-target?-source:使用指定版本的JDK編譯,比如:-source 1.4表示用JDK1.4的標(biāo)準(zhǔn)編譯,如果在源文件中使用了泛型,則用JDK1.4是不能編譯通過(guò)的。 ?-target:指定生成的class文件要運(yùn)行在哪個(gè)JVM版本,以后實(shí)際運(yùn)行的JVM版本必須要高于這個(gè)指定的版本。javac -source 1.4 Xxx.javajavac -target 1.4 Xxx.java -encoding默認(rèn)會(huì)使用系統(tǒng)環(huán)境的編碼,比如我們一般用的中文windows就是GBK編碼,所以直接javac時(shí)會(huì)用GBK編碼,而Java文件一般要使用utf-8,如果用GBK就會(huì)出現(xiàn)亂碼。?指定源文件的編碼格式,如果源文件是UTF-8編碼的,而-encoding GBK,則源文件就變成了亂碼(特別是有中文時(shí))。javac -encoding UTF-8 Xxx.java -verbose輸出詳細(xì)的編譯信息,包括:classpath、加載的類文件信息。比如,我寫了一個(gè)最簡(jiǎn)單的HelloWorld程序,在命令行中輸入:D:\Java>javac -verbose -encoding UTF-8 HelloWorld01.java輸出: [語(yǔ)法分析開(kāi)始時(shí)間 RegularFileObject[HelloWorld01.java]] [語(yǔ)法分析已完成, 用時(shí) 21 毫秒] [源文件的搜索路徑: .,D:\大三下\編譯原理\cup\java-cup-11a.jar,E:\java\jflex\lib\J //-sourcepath Flex.jar] [類文件的搜索路徑: C:\Java\jdk1.7.0_25\jre\lib\resources.jar,C:\Java\jdk1.7.0_25 //-classpath、-bootclasspath、-extdirs 省略............................................ [正在加載ZipFileIndexFileObject[C:\Java\jdk1.7.0_25\lib\ct.sym(META-INF/sym/rt.j ar/java/lang/Object.class)]] [正在加載ZipFileIndexFileObject[C:\Java\jdk1.7.0_25\lib\ct.sym(META-INF/sym/rt.j ar/java/lang/String.class)]] [正在檢查Demo] 省略............................................ [已寫入RegularFileObject[Demo.class]] [共 447 毫秒] 編寫一個(gè)程序時(shí),比如寫了一句:System.out.println(“hello”),實(shí)際上還需要加載:Object、PrintStream、String等類文件,而上面就顯示了加載的全部類文件。 其他命令-J <標(biāo)記> ?傳遞一些信息給 Java Launcher. javac -J-Xms48m Xxx.java //set the startup memory to 48M. -@<文件名>如果同時(shí)需要編譯數(shù)量較多的源文件(比如1000個(gè)),一個(gè)一個(gè)編譯是不現(xiàn)實(shí)的(當(dāng)然你可以直接 javac *.java ),比較好的方法是:將你想要編譯的源文件名都寫在一個(gè)文件中(比如sourcefiles.txt),其中每行寫一個(gè)文件名,如下所示:HelloWorld01.java HelloWorld02.java HelloWorld03.java 則使用下面的命令:javac @sourcefiles.txt編譯這三個(gè)源文件。 使用javac構(gòu)建項(xiàng)目這部分參考: https://blog.csdn.net/mingover/article/details/57083176一個(gè)簡(jiǎn)單的javac編譯新建兩個(gè)文件夾,src和 build src/com/yp/test/HelloWorld.java build/ ├─build └─src └─com └─yp └─test HelloWorld.java java文件非常簡(jiǎn)單 package com.yp.test; public class HelloWorld { public static void main(String[] args) { System.out.println("helloWorld"); } } 編譯: javac src/com/yp/test/HelloWorld.java -d build-d 表示編譯到 build文件夾下 查看build文件夾 ├─build │ └─com │ └─yp │ └─test │ HelloWorld.class │ └─src └─com └─yp └─test HelloWorld.java 運(yùn)行文件E:\codeplace\n_learn\java\javacmd> java com/yp/test/HelloWorld.class 錯(cuò)誤: 找不到或無(wú)法加載主類 build.com.yp.test.HelloWorld.class運(yùn)行時(shí)要指定main E:\codeplace\n_learn\java\javacmd\build> java com.yp.test.HelloWorld helloWorld 如果引用到多個(gè)其他的類,應(yīng)該怎么做呢 ?編譯E:\codeplace\n_learn\java\javacmd>javac src/com/yp/test/HelloWorld.java -sourcepath src -d build -g 1 -sourcepath 表示 從指定的源文件目錄中找到需要的.java文件并進(jìn)行編譯。 也可以用-cp指定編譯好的class的路徑 運(yùn)行,注意:運(yùn)行在build目錄下E:\codeplace\n_learn\java\javacmd\build>java com.yp.test.HelloWorld怎么打成jar包?生成: E:\codeplace\n_learn\java\javacmd\build>jar cvf h.jar * 運(yùn)行: E:\codeplace\n_learn\java\javacmd\build>java h.jar 錯(cuò)誤: 找不到或無(wú)法加載主類 h.jar這個(gè)錯(cuò)誤是沒(méi)有指定main類,所以類似這樣來(lái)指定: E:\codeplace\n_learn\java\javacmd\build>java -cp h.jar com.yp.test.HelloWorld 生成可以運(yùn)行的jar包需要指定jar包的應(yīng)用程序入口點(diǎn),用-e選項(xiàng): E:\codeplace\n_learn\java\javacmd\build> jar cvfe h.jar com.yp.test.HelloWorld * 已添加清單 正在添加: com/(輸入 = 0) (輸出 = 0)(存儲(chǔ)了 0%) 正在添加: com/yp/(輸入 = 0) (輸出 = 0)(存儲(chǔ)了 0%) 正在添加: com/yp/test/(輸入 = 0) (輸出 = 0)(存儲(chǔ)了 0%) 正在添加: com/yp/test/entity/(輸入 = 0) (輸出 = 0)(存儲(chǔ)了 0%) 正在添加: com/yp/test/entity/Cat.class(輸入 = 545) (輸出 = 319)(壓縮了 41%) 正在添加: com/yp/test/HelloWorld.class(輸入 = 844) (輸出 = 487)(壓縮了 42%) 直接運(yùn)行 java -jar h.jar 額外發(fā)現(xiàn) 指定了Main類后,jar包里面的 META-INF/MANIFEST.MF 是這樣的, 比原來(lái)多了一行Main-Class…. Manifest-Version: 1.0 Created-By: 1.8.0 (Oracle Corporation) Main-Class: com.yp.test.HelloWorld 如果類里有引用jar包呢?先下一個(gè)jar包 這里直接下 log4j * main函數(shù)改成 import com.yp.test.entity.Cat; import org.apache.log4j.Logger; public class HelloWorld { static Logger log = Logger.getLogger(HelloWorld.class); public static void main(String[] args) { Cat c = new Cat("keyboard"); log.info("這是log4j"); System.out.println("hello," + c.getName()); } } 現(xiàn)的文件是這樣的 ├─build ├─lib │ log4j-1.2.17.jar │ └─src └─com └─yp └─test │ HelloWorld.java │ └─entity Cat.java 這個(gè)時(shí)候 javac命令要接上 -cp ./lib/*.jar E:\codeplace\n_learn\java\javacmd>javac -encoding "utf8" src/com/yp/test/HelloWorld.java -sourcepath src -d build -g -cp ./lib/*.jar 運(yùn)行要加上-cp, -cp 選項(xiàng)貌似會(huì)把工作目錄給換了, 所以要加上 ;../build E:\codeplace\n_learn\java\javacmd\build>java -cp ../lib/log4j-1.2.17.jar;../build com.yp.test.HelloWorld 結(jié)果: log4j:WARN No appenders could be found for logger(com.yp.test.HelloWorld). log4j:WARN Please initialize the log4j system properly. log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info. hello,keyboard 由于沒(méi)有 log4j的配置文件,所以提示上面的問(wèn)題,往 build 里面加上 log4j.xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'> <appender name="stdout" class="org.apache.log4j.ConsoleAppender"> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n" /> </layout> </appender> <root> <level value="info" /> <appender-ref ref="stdout" /> </root> </log4j:configuration> 再運(yùn)行 E:\codeplace\n_learn\java\javacmd>java -cp lib/log4j-1.2.17.jar;build com.yp.tes t.HelloWorld 15:19:57,359 INFO [HelloWorld] 這是log4j hello,keyboard 說(shuō)明: 這個(gè)log4j配置文件,習(xí)慣的做法是放在src目錄下, 在編譯過(guò)程中 copy到build中的,但根據(jù)ant的做法,不是用javac的,而是用來(lái)處理,我猜測(cè)javac是不能copy的,如果想在命令行直接 使用,應(yīng)該是用cp命令主動(dòng)去執(zhí)行 copy操作ok 一個(gè)簡(jiǎn)單的java 工程就運(yùn)行完了 但是 貌似有些繁瑣, 需要手動(dòng)鍵入 java文件 以及相應(yīng)的jar包 很是麻煩, so 可以用 shell 來(lái)腳本來(lái)簡(jiǎn)化相關(guān)操作 shell 文件整理如下: #!/bin/bash echo "build start" JAR_PATH=libs BIN_PATH=bin SRC_PATH=src # java文件列表目錄 SRC_FILE_LIST_PATH=src/sources.list #生所有的java文件列表 放入列表文件中 rm -f $SRC_PATH/sources find $SRC_PATH/ -name *.java > $SRC_FILE_LIST_PATH #刪除舊的編譯文件 生成bin目錄 rm -rf $BIN_PATH/ mkdir $BIN_PATH/ #生成依賴jar包 列表 for file in ${JAR_PATH}/*.jar; do jarfile=${jarfile}:${file} done echo "jarfile = "$jarfile #編譯 通過(guò)-cp指定所有的引用jar包,將src下的所有java文件進(jìn)行編譯 javac -d $BIN_PATH/ -cp $jarfile @$SRC_FILE_LIST_PATH #運(yùn)行 通過(guò)-cp指定所有的引用jar包,指定入口函數(shù)運(yùn)行 java -cp $BIN_PATH$jarfile com.zuiapps.danmaku.server.Main 有一點(diǎn)需要注意的是, javac -d $BIN_PATH/ -cp $jarfile @$SRC_FILE_LIST_PATH 在要編譯的文件很多時(shí)候,一個(gè)個(gè)敲命令會(huì)顯得很長(zhǎng),也不方便修改,可以把要編譯的源文件列在文件中,在文件名前加@,這樣就可以對(duì)多個(gè)文件進(jìn)行編譯,以上就是吧java文件放到 $SRC_FILE_LIST_PATH 中去了 編譯 : 1. 需要編譯所有的java文件 2. 依賴的java 包都需要加入到 classpath 中去 3. 最后設(shè)置 編譯后的 class 文件存放目錄 即 -d bin/ 4. java文件過(guò)多是可以使用 @$SRC_FILE_LIST_PATH 把他們放到一個(gè)文件中去 運(yùn)行: 1.需要吧 編譯時(shí)設(shè)置的bin目錄和 所有jar包加入到 classpath 中去 javapjavap是jdk自帶的一個(gè)工具,可以對(duì)代碼反編譯,也可以查看java編譯器生成的字節(jié)碼。情況下,很少有人使用javap對(duì)class文件進(jìn)行反編譯,因?yàn)橛泻芏喑墒斓姆淳幾g工具可以使用,比如jad。但是,javap還可以查看java編譯器為我們生成的字節(jié)碼。通過(guò)它,可以對(duì)照源代碼和字節(jié)碼,從而了解很多編譯器內(nèi)部的工作。javap命令分解一個(gè)class文件,它根據(jù)options來(lái)決定到底輸出什么。如果沒(méi)有使用options,那么javap將會(huì)輸出包,類里的protected和public域以及類里的所有方法。javap將會(huì)把它們輸出在標(biāo)準(zhǔn)輸出上。來(lái)看這個(gè)例子,先編譯(javac)下面這個(gè)類。 import java.awt.*; import java.applet.*; public class DocFooter extends Applet { String date; String email; public void init() { resize(500,100); date = getParameter("LAST_UPDATED"); email = getParameter("EMAIL"); } } 在命令行上鍵入javap DocFooter后,輸出結(jié)果如下Compiled from “DocFooter.java” public class DocFooter extends java.applet.Applet { java.lang.String date; java.lang.String email; public DocFooter(); public void init(); } 如果加入了-c,即javap -c DocFooter,那么輸出結(jié)果如下Compiled from “DocFooter.java” public class DocFooter extends java.applet.Applet { java.lang.String date; java.lang.String email; public DocFooter(); Code: 0: aload_0 1: invokespecial #1 // Method java/applet/Applet."<init>":()V 4: return public void init(); Code: 0: aload_0 1: sipush 500 4: bipush 100 6: invokevirtual #2 // Method resize:(II)V 9: aload_0 10: aload_0 11: ldc #3 // String LAST_UPDATED 13: invokevirtual #4 // Method getParameter:(Ljava/lang/String;)Ljava/lang/String; 16: putfield #5 // Field date:Ljava/lang/String; 19: aload_0 20: aload_0 21: ldc #6 // String EMAIL 23: invokevirtual #4 // Method getParameter:(Ljava/lang/String;)Ljava/lang/String; 26: putfield #7 // Field email:Ljava/lang/String; 29: return } 上面輸出的內(nèi)容就是字節(jié)碼。用法摘要-help 幫助 -l 輸出行和變量的表 -public 只輸出public方法和域 -protected 只輸出public和protected類和成員 -package 只輸出包,public和protected類和成員,這是默認(rèn)的 -p -private 輸出所有類和成員 -s 輸出內(nèi)部類型簽名 -c 輸出分解后的代碼,例如,類中每一個(gè)方法內(nèi),包含java字節(jié)碼的指令, -verbose 輸出棧大小,方法參數(shù)的個(gè)數(shù) -constants 輸出靜態(tài)final常量 總結(jié)javap可以用于反編譯和查看編譯器編譯后的字節(jié)碼。平時(shí)一般用javap -c比較多,該命令用于列出每個(gè)方法所執(zhí)行的JVM指令,并顯示每個(gè)方法的字節(jié)碼的實(shí)際作用??梢酝ㄟ^(guò)字節(jié)碼和源代碼的對(duì)比,深入分析java的編譯原理,了解和解決各種Java原理級(jí)別的問(wèn)題。 參考文章https://blog.csdn.net/Anbernet/article/details/81449390https://www.cnblogs.com/luobiao320/p/7975442.htmlhttps://www.jianshu.com/p/f7330dbdc051https://www.jianshu.com/p/6a8997560b05https://blog.csdn.net/w372426096/article/details/81664431https://blog.csdn.net/qincidong/article/details/82492140 微信公眾號(hào) Java技術(shù)江湖如果大家想要實(shí)時(shí)關(guān)注我更新的文章以及分享的干貨的話,可以關(guān)注我的公眾號(hào)【Java技術(shù)江湖】一位阿里 Java 工程師的技術(shù)小站,作者黃小斜,專注 Java 相關(guān)技術(shù):SSM、SpringBoot、MySQL、分布式、中間件、集群、Linux、網(wǎng)絡(luò)、多線程,偶爾講點(diǎn)Docker、ELK,同時(shí)也分享技術(shù)干貨和學(xué)習(xí)經(jīng)驗(yàn),致力于Java全棧開(kāi)發(fā)!Java工程師必備學(xué)習(xí)資源:一些Java工程師常用學(xué)習(xí)資源,關(guān)注公眾號(hào)后,后臺(tái)回復(fù)關(guān)鍵字 “Java”即可免費(fèi)無(wú)套路獲取。 個(gè)人公眾號(hào):黃小斜作者是 985 碩士,螞蟻金服 JAVA 工程師,專注于 JAVA 后端技術(shù)棧:SpringBoot、MySQL、分布式、中間件、微服務(wù),同時(shí)也懂點(diǎn)投資理財(cái),偶爾講點(diǎn)算法和計(jì)算機(jī)理論基礎(chǔ),堅(jiān)持學(xué)習(xí)和寫作,相信終身學(xué)習(xí)的力量!程序員3T技術(shù)學(xué)習(xí)資源:一些程序員學(xué)習(xí)技術(shù)的資源大禮包,關(guān)注公眾號(hào)后,后臺(tái)回復(fù)關(guān)鍵字 “資料”即可免費(fèi)無(wú)套路獲取。
其中, 可能的選項(xiàng)包括:
-g 生成所有調(diào)試信息-g:none 不生成任何調(diào)試信息-g:{lines,vars,source} 只生成某些調(diào)試信息-nowarn 不生成任何警告-verbose 輸出有關(guān)編譯器正在執(zhí)行的操作的消息-deprecation 輸出使用已過(guò)時(shí)的 API 的源位置-classpath <路徑> 指定查找用戶類文件和注釋處理程序的位置-cp <路徑> 指定查找用戶類文件和注釋處理程序的位置-sourcepath <路徑> 指定查找輸入源文件的位置-bootclasspath <路徑> 覆蓋引導(dǎo)類文件的位置-extdirs <目錄> 覆蓋所安裝擴(kuò)展的位置-endorseddirs <目錄> 覆蓋簽名的標(biāo)準(zhǔn)路徑的位置-proc:{none,only} 控制是否執(zhí)行注釋處理和/或編譯。-processor [, , …] 要運(yùn)行的注釋處理程序的名稱; 繞過(guò)默認(rèn)的搜索進(jìn)程 -processorpath <路徑> 指定查找注釋處理程序的位置-d <目錄> 指定放置生成的類文件的位置-s <目錄> 指定放置生成的源文件的位置-implicit:{none,class} 指定是否為隱式引用文件生成類文件-encoding <編碼> 指定源文件使用的字符編碼-source <發(fā)行版> 提供與指定發(fā)行版的源兼容性-target <發(fā)行版> 生成特定 VM 版本的類文件-version 版本信息-help 輸出標(biāo)準(zhǔn)選項(xiàng)的提要-A關(guān)鍵字[=值] 傳遞給注釋處理程序的選項(xiàng)-X 輸出非標(biāo)準(zhǔn)選項(xiàng)的提要-J<標(biāo)記> 直接將 <標(biāo)記> 傳遞給運(yùn)行時(shí)系統(tǒng)-Werror 出現(xiàn)警告時(shí)終止編譯@<文件名> 從文件讀取選項(xiàng)和文件名
-g 生成所有調(diào)試信息
-g:none 不生成任何調(diào)試信息
-g:{lines,vars,source} 只生成某些調(diào)試信息
-nowarn 不生成任何警告
-verbose 輸出有關(guān)編譯器正在執(zhí)行的操作的消息
-deprecation 輸出使用已過(guò)時(shí)的 API 的源位置
-classpath <路徑> 指定查找用戶類文件和注釋處理程序的位置
-cp <路徑> 指定查找用戶類文件和注釋處理程序的位置
-sourcepath <路徑> 指定查找輸入源文件的位置
-bootclasspath <路徑> 覆蓋引導(dǎo)類文件的位置
-extdirs <目錄> 覆蓋所安裝擴(kuò)展的位置
-endorseddirs <目錄> 覆蓋簽名的標(biāo)準(zhǔn)路徑的位置
-proc:{none,only} 控制是否執(zhí)行注釋處理和/或編譯。
-processor [, , …] 要運(yùn)行的注釋處理程序的名稱; 繞過(guò)默認(rèn)的搜索進(jìn)程 -processorpath <路徑> 指定查找注釋處理程序的位置-d <目錄> 指定放置生成的類文件的位置-s <目錄> 指定放置生成的源文件的位置-implicit:{none,class} 指定是否為隱式引用文件生成類文件-encoding <編碼> 指定源文件使用的字符編碼-source <發(fā)行版> 提供與指定發(fā)行版的源兼容性-target <發(fā)行版> 生成特定 VM 版本的類文件-version 版本信息-help 輸出標(biāo)準(zhǔn)選項(xiàng)的提要-A關(guān)鍵字[=值] 傳遞給注釋處理程序的選項(xiàng)-X 輸出非標(biāo)準(zhǔn)選項(xiàng)的提要-J<標(biāo)記> 直接將 <標(biāo)記> 傳遞給運(yùn)行時(shí)系統(tǒng)-Werror 出現(xiàn)警告時(shí)終止編譯@<文件名> 從文件讀取選項(xiàng)和文件名
-processorpath <路徑> 指定查找注釋處理程序的位置
-d <目錄> 指定放置生成的類文件的位置
-s <目錄> 指定放置生成的源文件的位置
-implicit:{none,class} 指定是否為隱式引用文件生成類文件
-encoding <編碼> 指定源文件使用的字符編碼
-source <發(fā)行版> 提供與指定發(fā)行版的源兼容性
-target <發(fā)行版> 生成特定 VM 版本的類文件
-version 版本信息
-help 輸出標(biāo)準(zhǔn)選項(xiàng)的提要
-A關(guān)鍵字[=值] 傳遞給注釋處理程序的選項(xiàng)
-X 輸出非標(biāo)準(zhǔn)選項(xiàng)的提要
-J<標(biāo)記> 直接將 <標(biāo)記> 傳遞給運(yùn)行時(shí)系統(tǒng)
-Werror 出現(xiàn)警告時(shí)終止編譯
@<文件名> 從文件讀取選項(xiàng)和文件名
在詳細(xì)介紹javac命令之前,先看看這個(gè)classpath是什么
在dos下編譯java程序,就要用到classpath這個(gè)概念,尤其是在沒(méi)有設(shè)置環(huán)境變量的時(shí)候。classpath就是存放.class等編譯后文件的路徑。
javac:如果當(dāng)前你要編譯的java文件中引用了其它的類(比如說(shuō):繼承),但該引用類的.class文件不在當(dāng)前目錄下,這種情況下就需要在javac命令后面加上-classpath參數(shù),通過(guò)使用以下三種類型的方法 來(lái)指導(dǎo)編譯器在編譯的時(shí)候去指定的路徑下查找引用類。
(1).絕對(duì)路徑:javac -classpath c:/junit3.8.1/junit.jar Xxx.java(2).相對(duì)路徑:javac -classpath ../junit3.8.1/Junit.javr Xxx.java(3).系統(tǒng)變量:javac -classpath %CLASSPATH% Xxx.java (注意:%CLASSPATH%表示使用系統(tǒng)變量CLASSPATH的值進(jìn)行查找,這里假設(shè)Junit.jar的路徑就包含在CLASSPATH系統(tǒng)變量中)
(1).絕對(duì)路徑:javac -classpath c:/junit3.8.1/junit.jar Xxx.java
(2).相對(duì)路徑:javac -classpath ../junit3.8.1/Junit.javr Xxx.java
(3).系統(tǒng)變量:javac -classpath %CLASSPATH% Xxx.java (注意:%CLASSPATH%表示使用系統(tǒng)變量CLASSPATH的值進(jìn)行查找,這里假設(shè)Junit.jar的路徑就包含在CLASSPATH系統(tǒng)變量中)
對(duì)于一個(gè)普通的Javaweb項(xiàng)目,一般有這樣的配置:
1 WEB-INF/classes,lib才是classpath,WEB-INF/ 是資源目錄, 客戶端不能直接訪問(wèn)。2、WEB-INF/classes目錄存放src目錄java文件編譯之后的class文件,xml、properties等資源配置文件,這是一個(gè)定位資源的入口。3、引用classpath路徑下的文件,只需在文件名前加classpath:classpath:applicationContext-*.xml classpath:context/conf/controller.xml4、lib和classes同屬classpath,兩者的訪問(wèn)優(yōu)先級(jí)為: lib>classes。5、classpath 和 classpath* 區(qū)別:classpath:只會(huì)到你的class路徑中查找找文件; classpath*:不僅包含class路徑,還包括jar文件中(class路徑)進(jìn)行查找。
1 WEB-INF/classes,lib才是classpath,WEB-INF/ 是資源目錄, 客戶端不能直接訪問(wèn)。
2、WEB-INF/classes目錄存放src目錄java文件編譯之后的class文件,xml、properties等資源配置文件,這是一個(gè)定位資源的入口。
3、引用classpath路徑下的文件,只需在文件名前加classpath:
classpath:applicationContext-*.xml
classpath:context/conf/controller.xml
4、lib和classes同屬classpath,兩者的訪問(wèn)優(yōu)先級(jí)為: lib>classes。
5、classpath 和 classpath* 區(qū)別:
classpath:只會(huì)到你的class路徑中查找找文件; classpath*:不僅包含class路徑,還包括jar文件中(class路徑)進(jìn)行查找。
總結(jié):
(1).何時(shí)需要使用-classpath:當(dāng)你要編譯或執(zhí)行的類引用了其它的類,但被引用類的.class文件不在當(dāng)前目錄下時(shí),就需要通過(guò)-classpath來(lái)引入類
(2).何時(shí)需要指定路徑:當(dāng)你要編譯的類所在的目錄和你執(zhí)行javac命令的目錄不是同一個(gè)目錄時(shí),就需要指定源文件的路徑(CLASSPATH是用來(lái)指定.class路徑的,不是用來(lái)指定.java文件的路徑的)
(看清IDE及classpath本質(zhì))
現(xiàn)在只是說(shuō)說(shuō)Java Project和Web Project,那么二者有區(qū)別么?回答:沒(méi)有!都是Java語(yǔ)言的應(yīng)用,只是應(yīng)用場(chǎng)合不同罷了,那么他們的本質(zhì)到底是什么?回答:編譯后路徑!虛擬機(jī)執(zhí)行的是class文件而不是java文件,那么我們不管是何種項(xiàng)目都是寫的java文件,怎么就不一樣了呢?分成java和web兩種了呢?從.classpath入手來(lái)看,這個(gè)文件在每個(gè)項(xiàng)目目錄下都是存在的,很少有人打開(kāi)看吧,那么我們就來(lái)一起看吧。這是一個(gè)XML文件,使用文本編輯器打開(kāi)即可。這里展示一個(gè)web項(xiàng)目的.classpath
現(xiàn)在只是說(shuō)說(shuō)Java Project和Web Project,那么二者有區(qū)別么?回答:沒(méi)有!都是Java語(yǔ)言的應(yīng)用,只是應(yīng)用場(chǎng)合不同罷了,那么他們的本質(zhì)到底是什么?
回答:編譯后路徑!虛擬機(jī)執(zhí)行的是class文件而不是java文件,那么我們不管是何種項(xiàng)目都是寫的java文件,怎么就不一樣了呢?分成java和web兩種了呢?
從.classpath入手來(lái)看,這個(gè)文件在每個(gè)項(xiàng)目目錄下都是存在的,很少有人打開(kāi)看吧,那么我們就來(lái)一起看吧。這是一個(gè)XML文件,使用文本編輯器打開(kāi)即可。
這里展示一個(gè)web項(xiàng)目的.classpath
Xml代碼
<?xml version="1.0" encoding="UTF-8"?> <classpath> <classpathentry kind="src" path="src"/> <classpathentry kind="src" path="resources"/> <classpathentry kind="src" path="test"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="lib" path="lib/servlet-api.jar"/> <classpathentry kind="lib" path="webapp/WEB-INF/lib/struts2-core-2.1.8.1.jar"/> …… <classpathentry kind="output" path="webapp/WEB-INF/classes"/> </classpath>
XML文檔包含一個(gè)根元素,就是classpath,類路徑,那么這里面包含了什么信息呢?子元素是classpathentry,kind屬性區(qū)別了種 類信息,src源碼,con你看看后面的path就知道是JRE容器的信息。lib是項(xiàng)目依賴的第三方類庫(kù),output是src編譯后的位置。既然是web項(xiàng)目,那么就是WEB-INF/classes目錄,可能用MyEclipse的同學(xué)會(huì)說(shuō)他們那里是WebRoot或者是WebContext而不是webapp,有區(qū)別么?回答:完全沒(méi)有!既然看到了編譯路徑的本來(lái)面目后,還區(qū)分什么java項(xiàng)目和web項(xiàng)目么?回答:不區(qū)分!普通的java 項(xiàng)目你這樣寫就行了: ,看看Eclipse是不是這樣生成的?這個(gè)問(wèn)題解決了吧。 再說(shuō)說(shuō)webapp目錄命名的問(wèn)題,這個(gè)無(wú)所謂啊,web項(xiàng)目是要發(fā)布到服務(wù)器上的對(duì)吧,那么服務(wù)器讀取的是類文件和頁(yè)面文件吧,它不管源文件,它也無(wú)法去理解源文件。那么webapp目錄的命名有何關(guān)系呢?只要讓服務(wù)器找到不就行了。
XML文檔包含一個(gè)根元素,就是classpath,類路徑,那么這里面包含了什么信息呢?子元素是classpathentry,kind屬性區(qū)別了種 類信息,src源碼,con你看看后面的path就知道是JRE容器的信息。lib是項(xiàng)目依賴的第三方類庫(kù),output是src編譯后的位置。
既然是web項(xiàng)目,那么就是WEB-INF/classes目錄,可能用MyEclipse的同學(xué)會(huì)說(shuō)他們那里是WebRoot或者是WebContext而不是webapp,有區(qū)別么?回答:完全沒(méi)有!
既然看到了編譯路徑的本來(lái)面目后,還區(qū)分什么java項(xiàng)目和web項(xiàng)目么?回答:不區(qū)分!普通的java 項(xiàng)目你這樣寫就行了: ,看看Eclipse是不是這樣生成的?這個(gè)問(wèn)題解決了吧。
再說(shuō)說(shuō)webapp目錄命名的問(wèn)題,這個(gè)無(wú)所謂啊,web項(xiàng)目是要發(fā)布到服務(wù)器上的對(duì)吧,那么服務(wù)器讀取的是類文件和頁(yè)面文件吧,它不管源文件,它也無(wú)法去理解源文件。那么webapp目錄的命名有何關(guān)系呢?只要讓服務(wù)器找到不就行了。
?-g:在生成的class文件中包含所有調(diào)試信息(行號(hào)、變量、源文件) ?-g:none :在生成的class文件中不包含任何調(diào)試信息。這個(gè)參數(shù)在javac編譯中是看不到什么作用的,因?yàn)檎{(diào)試信息都在class文件中,而我們看不懂這個(gè)class文件。為了看出這個(gè)參數(shù)的作用,我們?cè)趀clipse中進(jìn)行實(shí)驗(yàn)。在eclipse中,我們經(jīng)常做的事就是“debug”,而在debug的時(shí)候,我們會(huì) ?加入“斷點(diǎn)”,這個(gè)是靠-g:lines起作用,如果不記錄行號(hào),則不能加斷點(diǎn)。 ?在“variables”窗口中查看當(dāng)前的變量,如下圖所示,這是靠-g:vars起作用,否則不能查看變量信息。 ?在多個(gè)文件之間來(lái)回調(diào)用,比如 A.java的main()方法中調(diào)用了B.java的fun()函數(shù),而我想看看程序進(jìn)入fun()后的狀態(tài),這是靠-g:source,如果沒(méi)有這個(gè)參數(shù),則不能查看B.java的源代碼。
?-g:在生成的class文件中包含所有調(diào)試信息(行號(hào)、變量、源文件) ?-g:none :在生成的class文件中不包含任何調(diào)試信息。
這個(gè)參數(shù)在javac編譯中是看不到什么作用的,因?yàn)檎{(diào)試信息都在class文件中,而我們看不懂這個(gè)class文件。
為了看出這個(gè)參數(shù)的作用,我們?cè)趀clipse中進(jìn)行實(shí)驗(yàn)。在eclipse中,我們經(jīng)常做的事就是“debug”,而在debug的時(shí)候,我們會(huì) ?加入“斷點(diǎn)”,這個(gè)是靠-g:lines起作用,如果不記錄行號(hào),則不能加斷點(diǎn)。 ?在“variables”窗口中查看當(dāng)前的變量,如下圖所示,這是靠-g:vars起作用,否則不能查看變量信息。 ?在多個(gè)文件之間來(lái)回調(diào)用,比如 A.java的main()方法中調(diào)用了B.java的fun()函數(shù),而我想看看程序進(jìn)入fun()后的狀態(tài),這是靠-g:source,如果沒(méi)有這個(gè)參數(shù),則不能查看B.java的源代碼。
-bootclasspath和-extdirs 幾乎不需要用的,因?yàn)樗怯脕?lái)改變 “引導(dǎo)類”和“擴(kuò)展類”。 ?引導(dǎo)類(組成Java平臺(tái)的類):Java\jdk1.7.0_25\jre\lib\rt.jar等,用-bootclasspath設(shè)置。 ?擴(kuò)展類:Java\jdk1.7.0_25\jre\lib\ext目錄中的文件,用-extdirs設(shè)置。 ?用戶自定義類:用-classpath設(shè)置。我們用-verbose編譯后出現(xiàn)的“類文件的搜索路徑”,就是由上面三個(gè)路徑組成,如下:
-bootclasspath和-extdirs 幾乎不需要用的,因?yàn)樗怯脕?lái)改變 “引導(dǎo)類”和“擴(kuò)展類”。 ?引導(dǎo)類(組成Java平臺(tái)的類):Java\jdk1.7.0_25\jre\lib\rt.jar等,用-bootclasspath設(shè)置。 ?擴(kuò)展類:Java\jdk1.7.0_25\jre\lib\ext目錄中的文件,用-extdirs設(shè)置。 ?用戶自定義類:用-classpath設(shè)置。
我們用-verbose編譯后出現(xiàn)的“類文件的搜索路徑”,就是由上面三個(gè)路徑組成,如下:
[類文件的搜索路徑: C:\Java\jdk1.7.0_25\jre\lib\resources.jar,C:\Java\jdk1.7.0_25 \jre\lib\rt.jar,C:\Java\jdk1.7.0_25\jre\lib\sunrsasign.jar,C:\Java\jdk1.7.0_25\j re\lib\jsse.jar,C:\Java\jdk1.7.0_25\jre\lib\jce.jar,C:\Java\jdk1.7.0_25\jre\lib\ charsets.jar,C:\Java\jdk1.7.0_25\jre\lib\jfr.jar,C:\Java\jdk1.7.0_25\jre\classes ,C:\Java\jdk1.7.0_25\jre\lib\ext\access-bridge-32.jar,C:\Java\jdk1.7.0_25\jre\li b\ext\DNSns.jar,C:\Java\jdk1.7.0_25\jre\lib\ext\jaccess.jar,C:\Java\jdk1.7.0_25\ jre\lib\ext\localedata.jar,C:\Java\jdk1.7.0_25\jre\lib\ext\sunec.jar,C:\Java\jdk 1.7.0_25\jre\lib\ext\sunjce_provider.jar,C:\Java\jdk1.7.0_25\jre\lib\ext\sunmsca pi.jar,C:\Java\jdk1.7.0_25\jre\lib\ext\sunpkcs11.jar,C:\Java\jdk1.7.0_25\jre\lib \ext\zipfs.jar,..\bin]
如果利用 -bootclasspath 重新定義: javac -bootclasspath src Xxx.java,則會(huì)出現(xiàn)下面錯(cuò)誤:
致命錯(cuò)誤: 在類路徑或引導(dǎo)類路徑中找不到程序包 java.lang
?-classpath(-cp)指定你依賴的類的class文件的查找位置。在Linux中,用“:”分隔classpath,而在windows中,用“;”分隔。 ?-sourcepath指定你依賴的類的java文件的查找位置。
舉個(gè)例子,
public class A { public static void main(String[] args) { B b = new B(); b.print(); } } public class B { public void print() { System.out.println("old"); } }
目錄結(jié)構(gòu)如下:
sourcepath //此處為當(dāng)前目錄
|-src |-com |- B.java |- A.java |-bin |- B.class //是 B.java
編譯后的類文件
如果要編譯 A.java,則必須要讓編譯器找到類B的位置,你可以指定B.class的位置,也可以是B.java的位置,也可以同時(shí)都存在。
javac -classpath bin src/A.java //查找到B.class javac -sourcepath src/com src/A.java //查找到B.java javac -sourcepath src/com -classpath bin src/A.java //同時(shí)查找到B.class和B.java
如果同時(shí)找到了B.class和B.java,則: ?如果B.class和B.java內(nèi)容一致,則遵循B.class。 ?如果B.class和B.java內(nèi)容不一致,則遵循B.java,并編譯B.java。
以上規(guī)則可以通過(guò) -verbose選項(xiàng)看出。
?d就是 destination,用于指定.class文件的生成目錄,在eclipse中,源文件都在src中,編譯的class文件都是在bin目錄中。
這里我用來(lái)實(shí)現(xiàn)一下這個(gè)功能,假設(shè)項(xiàng)目名稱為project,此目錄為當(dāng)前目錄,且在src/com目錄中有一個(gè)Main.java文件?!?/p>
package com; public class Main { public static void main(String[] args) { System.out.println("Hello"); } } javac -d bin src/com/Main.java
上面的語(yǔ)句將Main.class生成在bin/com目錄下。
?如果有文件為A.java(其中有類A),且在類A中使用了類B,類B在B.java中,則編譯A.java時(shí),默認(rèn)會(huì)自動(dòng)編譯B.java,且生成B.class。 ?implicit:none:不自動(dòng)生成隱式引用的類文件。 ?implicit:class(默認(rèn)):自動(dòng)生成隱式引用的類文件。
public class A { public static void main(String[] args) { B b = new B(); } } public class B { } 如果使用: javac -implicit:none A.java
則不會(huì)生成 B.class。
?-source:使用指定版本的JDK編譯,比如:-source 1.4表示用JDK1.4的標(biāo)準(zhǔn)編譯,如果在源文件中使用了泛型,則用JDK1.4是不能編譯通過(guò)的。 ?-target:指定生成的class文件要運(yùn)行在哪個(gè)JVM版本,以后實(shí)際運(yùn)行的JVM版本必須要高于這個(gè)指定的版本。
javac -source 1.4 Xxx.java
javac -target 1.4 Xxx.java
默認(rèn)會(huì)使用系統(tǒng)環(huán)境的編碼,比如我們一般用的中文windows就是GBK編碼,所以直接javac時(shí)會(huì)用GBK編碼,而Java文件一般要使用utf-8,如果用GBK就會(huì)出現(xiàn)亂碼。
?指定源文件的編碼格式,如果源文件是UTF-8編碼的,而-encoding GBK,則源文件就變成了亂碼(特別是有中文時(shí))。
javac -encoding UTF-8 Xxx.java
輸出詳細(xì)的編譯信息,包括:classpath、加載的類文件信息。
比如,我寫了一個(gè)最簡(jiǎn)單的HelloWorld程序,在命令行中輸入:
D:\Java>javac -verbose -encoding UTF-8 HelloWorld01.java
輸出:
[語(yǔ)法分析開(kāi)始時(shí)間 RegularFileObject[HelloWorld01.java]] [語(yǔ)法分析已完成, 用時(shí) 21 毫秒] [源文件的搜索路徑: .,D:\大三下\編譯原理\cup\java-cup-11a.jar,E:\java\jflex\lib\J //-sourcepath Flex.jar] [類文件的搜索路徑: C:\Java\jdk1.7.0_25\jre\lib\resources.jar,C:\Java\jdk1.7.0_25 //-classpath、-bootclasspath、-extdirs 省略............................................ [正在加載ZipFileIndexFileObject[C:\Java\jdk1.7.0_25\lib\ct.sym(META-INF/sym/rt.j ar/java/lang/Object.class)]] [正在加載ZipFileIndexFileObject[C:\Java\jdk1.7.0_25\lib\ct.sym(META-INF/sym/rt.j ar/java/lang/String.class)]] [正在檢查Demo] 省略............................................ [已寫入RegularFileObject[Demo.class]] [共 447 毫秒]
編寫一個(gè)程序時(shí),比如寫了一句:System.out.println(“hello”),實(shí)際上還需要加載:Object、PrintStream、String等類文件,而上面就顯示了加載的全部類文件。
-J <標(biāo)記> ?傳遞一些信息給 Java Launcher.
javac -J-Xms48m Xxx.java //set the startup memory to 48M.
-@<文件名>
如果同時(shí)需要編譯數(shù)量較多的源文件(比如1000個(gè)),一個(gè)一個(gè)編譯是不現(xiàn)實(shí)的(當(dāng)然你可以直接 javac *.java ),比較好的方法是:將你想要編譯的源文件名都寫在一個(gè)文件中(比如sourcefiles.txt),其中每行寫一個(gè)文件名,如下所示:HelloWorld01.java HelloWorld02.java HelloWorld03.java
如果同時(shí)需要編譯數(shù)量較多的源文件(比如1000個(gè)),一個(gè)一個(gè)編譯是不現(xiàn)實(shí)的(當(dāng)然你可以直接 javac *.java ),比較好的方法是:將你想要編譯的源文件名都寫在一個(gè)文件中(比如sourcefiles.txt),其中每行寫一個(gè)文件名,如下所示:
HelloWorld01.java HelloWorld02.java HelloWorld03.java
則使用下面的命令:
javac @sourcefiles.txt
編譯這三個(gè)源文件。
這部分參考: https://blog.csdn.net/mingover/article/details/57083176
一個(gè)簡(jiǎn)單的javac編譯
新建兩個(gè)文件夾,src和 build src/com/yp/test/HelloWorld.java build/
├─build └─src └─com └─yp └─test HelloWorld.java
java文件非常簡(jiǎn)單
package com.yp.test; public class HelloWorld { public static void main(String[] args) { System.out.println("helloWorld"); } }
編譯: javac src/com/yp/test/HelloWorld.java -d build
-d 表示編譯到 build文件夾下
查看build文件夾 ├─build │ └─com │ └─yp │ └─test │ HelloWorld.class │ └─src └─com └─yp └─test HelloWorld.java
運(yùn)行文件
E:\codeplace\n_learn\java\javacmd> java com/yp/test/HelloWorld.class 錯(cuò)誤: 找不到或無(wú)法加載主類 build.com.yp.test.HelloWorld.class運(yùn)行時(shí)要指定main E:\codeplace\n_learn\java\javacmd\build> java com.yp.test.HelloWorld helloWorld
E:\codeplace\n_learn\java\javacmd> java com/yp/test/HelloWorld.class 錯(cuò)誤: 找不到或無(wú)法加載主類 build.com.yp.test.HelloWorld.class
運(yùn)行時(shí)要指定main E:\codeplace\n_learn\java\javacmd\build> java com.yp.test.HelloWorld helloWorld
如果引用到多個(gè)其他的類,應(yīng)該怎么做呢 ?
編譯E:\codeplace\n_learn\java\javacmd>javac src/com/yp/test/HelloWorld.java -sourcepath src -d build -g 1 -sourcepath 表示 從指定的源文件目錄中找到需要的.java文件并進(jìn)行編譯。 也可以用-cp指定編譯好的class的路徑 運(yùn)行,注意:運(yùn)行在build目錄下E:\codeplace\n_learn\java\javacmd\build>java com.yp.test.HelloWorld
編譯
E:\codeplace\n_learn\java\javacmd>javac src/com/yp/test/HelloWorld.java -sourcepath src -d build -g 1 -sourcepath 表示 從指定的源文件目錄中找到需要的.java文件并進(jìn)行編譯。 也可以用-cp指定編譯好的class的路徑 運(yùn)行,注意:運(yùn)行在build目錄下
E:\codeplace\n_learn\java\javacmd\build>java com.yp.test.HelloWorld
怎么打成jar包?
生成: E:\codeplace\n_learn\java\javacmd\build>jar cvf h.jar * 運(yùn)行: E:\codeplace\n_learn\java\javacmd\build>java h.jar 錯(cuò)誤: 找不到或無(wú)法加載主類 h.jar這個(gè)錯(cuò)誤是沒(méi)有指定main類,所以類似這樣來(lái)指定: E:\codeplace\n_learn\java\javacmd\build>java -cp h.jar com.yp.test.HelloWorld
生成: E:\codeplace\n_learn\java\javacmd\build>jar cvf h.jar * 運(yùn)行: E:\codeplace\n_learn\java\javacmd\build>java h.jar 錯(cuò)誤: 找不到或無(wú)法加載主類 h.jar
這個(gè)錯(cuò)誤是沒(méi)有指定main類,所以類似這樣來(lái)指定: E:\codeplace\n_learn\java\javacmd\build>java -cp h.jar com.yp.test.HelloWorld
生成可以運(yùn)行的jar包
需要指定jar包的應(yīng)用程序入口點(diǎn),用-e選項(xiàng):
E:\codeplace\n_learn\java\javacmd\build> jar cvfe h.jar com.yp.test.HelloWorld * 已添加清單 正在添加: com/(輸入 = 0) (輸出 = 0)(存儲(chǔ)了 0%) 正在添加: com/yp/(輸入 = 0) (輸出 = 0)(存儲(chǔ)了 0%) 正在添加: com/yp/test/(輸入 = 0) (輸出 = 0)(存儲(chǔ)了 0%) 正在添加: com/yp/test/entity/(輸入 = 0) (輸出 = 0)(存儲(chǔ)了 0%) 正在添加: com/yp/test/entity/Cat.class(輸入 = 545) (輸出 = 319)(壓縮了 41%) 正在添加: com/yp/test/HelloWorld.class(輸入 = 844) (輸出 = 487)(壓縮了 42%)
直接運(yùn)行
java -jar h.jar 額外發(fā)現(xiàn) 指定了Main類后,jar包里面的 META-INF/MANIFEST.MF 是這樣的, 比原來(lái)多了一行Main-Class…. Manifest-Version: 1.0 Created-By: 1.8.0 (Oracle Corporation) Main-Class: com.yp.test.HelloWorld
如果類里有引用jar包呢?
先下一個(gè)jar包 這里直接下 log4j
* main函數(shù)改成 import com.yp.test.entity.Cat; import org.apache.log4j.Logger; public class HelloWorld { static Logger log = Logger.getLogger(HelloWorld.class); public static void main(String[] args) { Cat c = new Cat("keyboard"); log.info("這是log4j"); System.out.println("hello," + c.getName()); } }
現(xiàn)的文件是這樣的
├─build ├─lib │ log4j-1.2.17.jar │ └─src └─com └─yp └─test │ HelloWorld.java │ └─entity Cat.java
這個(gè)時(shí)候 javac命令要接上 -cp ./lib/*.jar E:\codeplace\n_learn\java\javacmd>javac -encoding "utf8" src/com/yp/test/HelloWorld.java -sourcepath src -d build -g -cp ./lib/*.jar 運(yùn)行要加上-cp, -cp 選項(xiàng)貌似會(huì)把工作目錄給換了, 所以要加上 ;../build E:\codeplace\n_learn\java\javacmd\build>java -cp ../lib/log4j-1.2.17.jar;../build com.yp.test.HelloWorld
結(jié)果:
log4j:WARN No appenders could be found for logger(com.yp.test.HelloWorld). log4j:WARN Please initialize the log4j system properly. log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info. hello,keyboard
由于沒(méi)有 log4j的配置文件,所以提示上面的問(wèn)題,往 build 里面加上 log4j.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'> <appender name="stdout" class="org.apache.log4j.ConsoleAppender"> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n" /> </layout> </appender> <root> <level value="info" /> <appender-ref ref="stdout" /> </root> </log4j:configuration>
再運(yùn)行
E:\codeplace\n_learn\java\javacmd>java -cp lib/log4j-1.2.17.jar;build com.yp.tes t.HelloWorld 15:19:57,359 INFO [HelloWorld] 這是log4j hello,keyboard
說(shuō)明: 這個(gè)log4j配置文件,習(xí)慣的做法是放在src目錄下, 在編譯過(guò)程中 copy到build中的,但根據(jù)ant的做法,不是用javac的,而是用來(lái)處理,我猜測(cè)javac是不能copy的,如果想在命令行直接 使用,應(yīng)該是用cp命令主動(dòng)去執(zhí)行 copy操作
ok 一個(gè)簡(jiǎn)單的java 工程就運(yùn)行完了 但是 貌似有些繁瑣, 需要手動(dòng)鍵入 java文件 以及相應(yīng)的jar包 很是麻煩, so 可以用 shell 來(lái)腳本來(lái)簡(jiǎn)化相關(guān)操作 shell 文件整理如下:
#!/bin/bash echo "build start" JAR_PATH=libs BIN_PATH=bin SRC_PATH=src # java文件列表目錄 SRC_FILE_LIST_PATH=src/sources.list #生所有的java文件列表 放入列表文件中 rm -f $SRC_PATH/sources find $SRC_PATH/ -name *.java > $SRC_FILE_LIST_PATH #刪除舊的編譯文件 生成bin目錄 rm -rf $BIN_PATH/ mkdir $BIN_PATH/ #生成依賴jar包 列表 for file in ${JAR_PATH}/*.jar; do jarfile=${jarfile}:${file} done echo "jarfile = "$jarfile #編譯 通過(guò)-cp指定所有的引用jar包,將src下的所有java文件進(jìn)行編譯 javac -d $BIN_PATH/ -cp $jarfile @$SRC_FILE_LIST_PATH #運(yùn)行 通過(guò)-cp指定所有的引用jar包,指定入口函數(shù)運(yùn)行 java -cp $BIN_PATH$jarfile com.zuiapps.danmaku.server.Main
有一點(diǎn)需要注意的是, javac -d $BIN_PATH/ -cp $jarfile @$SRC_FILE_LIST_PATH 在要編譯的文件很多時(shí)候,一個(gè)個(gè)敲命令會(huì)顯得很長(zhǎng),也不方便修改,可以把要編譯的源文件列在文件中,在文件名前加@,這樣就可以對(duì)多個(gè)文件進(jìn)行編譯,以上就是吧java文件放到 $SRC_FILE_LIST_PATH 中去了
有一點(diǎn)需要注意的是, javac -d $BIN_PATH/ -cp $jarfile @$SRC_FILE_LIST_PATH 在要編譯的文件很多時(shí)候,一個(gè)個(gè)敲命令會(huì)顯得很長(zhǎng),也不方便修改,
可以把要編譯的源文件列在文件中,在文件名前加@,這樣就可以對(duì)多個(gè)文件進(jìn)行編譯,
以上就是吧java文件放到 $SRC_FILE_LIST_PATH 中去了
編譯 : 1. 需要編譯所有的java文件 2. 依賴的java 包都需要加入到 classpath 中去 3. 最后設(shè)置 編譯后的 class 文件存放目錄 即 -d bin/ 4. java文件過(guò)多是可以使用 @$SRC_FILE_LIST_PATH 把他們放到一個(gè)文件中去 運(yùn)行: 1.需要吧 編譯時(shí)設(shè)置的bin目錄和 所有jar包加入到 classpath 中去
javap是jdk自帶的一個(gè)工具,可以對(duì)代碼反編譯,也可以查看java編譯器生成的字節(jié)碼。情況下,很少有人使用javap對(duì)class文件進(jìn)行反編譯,因?yàn)橛泻芏喑墒斓姆淳幾g工具可以使用,比如jad。但是,javap還可以查看java編譯器為我們生成的字節(jié)碼。通過(guò)它,可以對(duì)照源代碼和字節(jié)碼,從而了解很多編譯器內(nèi)部的工作。javap命令分解一個(gè)class文件,它根據(jù)options來(lái)決定到底輸出什么。如果沒(méi)有使用options,那么javap將會(huì)輸出包,類里的protected和public域以及類里的所有方法。javap將會(huì)把它們輸出在標(biāo)準(zhǔn)輸出上。來(lái)看這個(gè)例子,先編譯(javac)下面這個(gè)類。
javap是jdk自帶的一個(gè)工具,可以對(duì)代碼反編譯,也可以查看java編譯器生成的字節(jié)碼。
情況下,很少有人使用javap對(duì)class文件進(jìn)行反編譯,因?yàn)橛泻芏喑墒斓姆淳幾g工具可以使用,比如jad。但是,javap還可以查看java編譯器為我們生成的字節(jié)碼。通過(guò)它,可以對(duì)照源代碼和字節(jié)碼,從而了解很多編譯器內(nèi)部的工作。
javap命令分解一個(gè)class文件,它根據(jù)options來(lái)決定到底輸出什么。如果沒(méi)有使用options,那么javap將會(huì)輸出包,類里的protected和public域以及類里的所有方法。javap將會(huì)把它們輸出在標(biāo)準(zhǔn)輸出上。來(lái)看這個(gè)例子,先編譯(javac)下面這個(gè)類。
import java.awt.*; import java.applet.*; public class DocFooter extends Applet { String date; String email; public void init() { resize(500,100); date = getParameter("LAST_UPDATED"); email = getParameter("EMAIL"); } }
在命令行上鍵入javap DocFooter后,輸出結(jié)果如下
Compiled from “DocFooter.java”
public class DocFooter extends java.applet.Applet { java.lang.String date; java.lang.String email; public DocFooter(); public void init(); }
如果加入了-c,即javap -c DocFooter,那么輸出結(jié)果如下
public class DocFooter extends java.applet.Applet { java.lang.String date; java.lang.String email; public DocFooter(); Code: 0: aload_0 1: invokespecial #1 // Method java/applet/Applet."<init>":()V 4: return public void init(); Code: 0: aload_0 1: sipush 500 4: bipush 100 6: invokevirtual #2 // Method resize:(II)V 9: aload_0 10: aload_0 11: ldc #3 // String LAST_UPDATED 13: invokevirtual #4 // Method getParameter:(Ljava/lang/String;)Ljava/lang/String; 16: putfield #5 // Field date:Ljava/lang/String; 19: aload_0 20: aload_0 21: ldc #6 // String EMAIL 23: invokevirtual #4 // Method getParameter:(Ljava/lang/String;)Ljava/lang/String; 26: putfield #7 // Field email:Ljava/lang/String; 29: return }
上面輸出的內(nèi)容就是字節(jié)碼。
用法摘要
-help 幫助 -l 輸出行和變量的表 -public 只輸出public方法和域 -protected 只輸出public和protected類和成員 -package 只輸出包,public和protected類和成員,這是默認(rèn)的 -p -private 輸出所有類和成員 -s 輸出內(nèi)部類型簽名 -c 輸出分解后的代碼,例如,類中每一個(gè)方法內(nèi),包含java字節(jié)碼的指令, -verbose 輸出棧大小,方法參數(shù)的個(gè)數(shù) -constants 輸出靜態(tài)final常量 總結(jié)
javap可以用于反編譯和查看編譯器編譯后的字節(jié)碼。平時(shí)一般用javap -c比較多,該命令用于列出每個(gè)方法所執(zhí)行的JVM指令,并顯示每個(gè)方法的字節(jié)碼的實(shí)際作用??梢酝ㄟ^(guò)字節(jié)碼和源代碼的對(duì)比,深入分析java的編譯原理,了解和解決各種Java原理級(jí)別的問(wèn)題。
https://blog.csdn.net/Anbernet/article/details/81449390
https://www.cnblogs.com/luobiao320/p/7975442.html
https://www.jianshu.com/p/f7330dbdc051
https://www.jianshu.com/p/6a8997560b05
https://blog.csdn.net/w372426096/article/details/81664431
https://blog.csdn.net/qincidong/article/details/82492140
如果大家想要實(shí)時(shí)關(guān)注我更新的文章以及分享的干貨的話,可以關(guān)注我的公眾號(hào)【Java技術(shù)江湖】一位阿里 Java 工程師的技術(shù)小站,作者黃小斜,專注 Java 相關(guān)技術(shù):SSM、SpringBoot、MySQL、分布式、中間件、集群、Linux、網(wǎng)絡(luò)、多線程,偶爾講點(diǎn)Docker、ELK,同時(shí)也分享技術(shù)干貨和學(xué)習(xí)經(jīng)驗(yàn),致力于Java全棧開(kāi)發(fā)!
Java工程師必備學(xué)習(xí)資源:一些Java工程師常用學(xué)習(xí)資源,關(guān)注公眾號(hào)后,后臺(tái)回復(fù)關(guān)鍵字 “Java”即可免費(fèi)無(wú)套路獲取。
作者是 985 碩士,螞蟻金服 JAVA 工程師,專注于 JAVA 后端技術(shù)棧:SpringBoot、MySQL、分布式、中間件、微服務(wù),同時(shí)也懂點(diǎn)投資理財(cái),偶爾講點(diǎn)算法和計(jì)算機(jī)理論基礎(chǔ),堅(jiān)持學(xué)習(xí)和寫作,相信終身學(xué)習(xí)的力量!
程序員3T技術(shù)學(xué)習(xí)資源:一些程序員學(xué)習(xí)技術(shù)的資源大禮包,關(guān)注公眾號(hào)后,后臺(tái)回復(fù)關(guān)鍵字 “資料”即可免費(fèi)無(wú)套路獲取。
網(wǎng)站名稱:夯實(shí)Java基礎(chǔ)系列20:從IDE的實(shí)現(xiàn)原理聊起,談?wù)勀切┠晡覀冇眠^(guò)的Java命令 文章地址:http://jinyejixie.com/article20/jpdhco.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供移動(dòng)網(wǎng)站建設(shè)、微信公眾號(hào)、網(wǎng)站改版、關(guān)鍵詞優(yōu)化、企業(yè)建站、網(wǎng)站導(dǎo)航
廣告
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容
全網(wǎng)營(yíng)銷推廣知識(shí)
同城分類信息