JAVA学习笔记

原创 2013年12月04日 20:56:46

第三章 面向对象

 

1. 类的成员变量会默认初始化,而局部变量不能,必须先赋值再使用。所有的引用类型(除了八种基本类型之外的变量类型),默认null。基本类型只占用一块内存;引用类型占用两块(名字,实体)。引用即为C/C++中的指针

 

2. 类是静态的概念,存放在code seg;对象需分配的内存大小只有在运行期间(javac是编译期间,java是运行期间)才能知道,new出的东西放在堆内存里。堆内存区比较大,动态分配内存。如果对象不再使用,由垃圾回收系统回收内存。类的成员变量(除了静态变量)在不同的对象中有不同值,方法只有一份(代码区中),执行的时候才占用内存

 

3. 函数调用中传递参数时,基本类型传递数据值本身,引用类型传递对象的引用

 

4. codedatastackheap 局部变量分布在stack seg字符串常量data seg

 

5. this一般出现在方法的定义中,代表使用该方法的对象的引用;也可以用于处理方法中成员变量与参数重名的情况

 

6. static变量是静态的变量,存放在dataseg 。字符串常量分配在 data segment。用static声明的方法是静态方法,在调用该方法时,不会将对象的引用传递给它,所以static方法中不能访问非static的成员,因为非静态成员专属于一个实例化对象,必须new一个对象才能够使用。

 

7. 解决类的命名冲突问题,引入包(package)机制,提供类的多重类命名空间。约定俗成的包名:公司的域名颠倒过来—com.bjsxt.java140. package语句是java源文件的第一条语句,指明该文件中定义的类所在的包(若缺省该语句,则指定为无名包)

         如果要把类放入包中,第一句话要写package,包层数随意,编译出来的class文件,必须位于正确的目录里面(和包的层次要完全一致),该类的源代码可能会产生影响,最好删除或者转移到别的目录中。

         如果想要在另外一个类中用包中的类,必须在文件的开头用import引入类全名,当然,同一个包中的类不需要import

         Class文件的最上层包所在的目录(或者是打到jar包中,jar包所在的目录)必须在classpath中,(例如:com.sxt.abc.classabc.class最上层的包是comcom位于 d:\java,那么d:\java必须在classpath中)才能保证其他类能找到它。

命令行中执行一个类,需要写全包名。如果两个项目都设了classpath,但是又有重名的类,会很麻烦,分不清哪个类,要注意classpath中的先后顺序Eclipse中不存在这个问题。每一个自己的project应该有自己专门的classpath,跟其他的classpath不共享。

 

8. j2sdk 中主要的包

Java.lang 包含java语言的核心类,StringMathIntegerSystemThread。这个包中的类不需要import,直接能用

Java.awt

Java.applet现在已经不怎么流行了

Java.net包装了TCP,UDP网络上的应用程序

Java.io输入输出流

Java.util实用工具类,如定义系统特性、使用与日期日历相关的函数

        

         可以将类打成jar包,供他人使用, 首先将命令行路径,定位到最上层的包的上一层,然后输入打包语句“jar –cvf xx.jar *.*”,jar包生成目录与最上层包同级

         可以将jar的路径设为classpath

 

9. java只支持单继承,c++支持多重继承

         Java权限修饰符一方面可以修饰成员变量或者成员方法,另一方面可以修饰classDefault修饰,包外的都无法访问,子类也不能。Protected是为了让包外的子类访问。

Private类型的属性,子类无法直接使用,只能通过调用父类方法使用。父类引用指向子类对象,该引用也无法调用父类的private属性。

对于class,只能用public(谁都可以访问)default修饰(同一个包中其他类能访问)

所有的关键字,都可以修饰内部类

 

10. 重载overload):在同一个类中,方法同名,同返回值,参数不同(类型不同or个数不同)

         重写overwrite/override):子类中根据需要对从基类中继承来的方法进行重写(将会覆盖掉基类方法),方法同名,同返回值,同参数列表。不能使用比被重写的方法更严格的访问权限。如果要重写一个方法,最好去复制原方法的声明,以免出错。

 

11. super是当前对象中的父类对象的引用,this指向当前对象的引用

 

12. 子类的构造过程中,必须调用基类的构造方法。子类在自己的构造方法中,使用superargument_list)调用基类的构造方法,使用thisargument_list)调用本类的其他构造方法。如果调用super,必须写在子类构造方法的第一行。

         子类的构造方法中,如果没有显示的调用基类构造方法或者自身的构造方法,则系统默认调用基类的无参构造方法,而如果基类中又没有无参构造方法,则编译出错。

 

13. 一个字符串和另外一种类型做连接操作时候,例如:” ” + int/对象,另外一种类型自动调用该对象类的toString() 方法,转换成String类型,再做连接。

 

14. hashcode 哈希编码 独一无二的代表一个对象,通过他可以找到这个对象所在的位置。

 

15. 默认的equals方法,与==意义相同,都是比较是否指向同一个对象。所以,如果需要比较不同对象之间具体内容的不同,需要重写。

         关键词instanceof是用来判断一个对象实例是否是另外一个类或接口的实现,或者是否是其子类子接口的实现ooinstanceof TypeName 第一个参数是对象实例名,第二个参数是具体的类名或接口名

       如果需要的参数,是一个父类对象的引用,可以传入子类对象,父类引用指向子类对象,称为向上转型(upcasting),但是父类的引用不能访问子类对象新增的成员(成员和方法),实质上就是:这个引用只能看到子类对象中包含的父类对象。反之称为向下转型(downcasting),又称为强制转换。这种父类引用,可以强制类型转换为子类对象,因为它实际上就是指向的子类对象,不能强制转换成其他的类型。

 

16. 程序的可扩展性

       1)单独定义好多个方法,最原始的途径,无扩展性可言

       2)在一个方法的参数中,定义父类的引用,在实际用的时候传入子类对象,在方法中判断此对象属于哪个子类,然后再去执行其中的方法,或者调用其中的成员变量。程序的可扩展性比单独定义好多个方法强

       3)多态,不需要判断传入子对象的类型,自动动态绑定所需要的方法,可扩展性达到了最好

 

17. 动态绑定 Dynamicbinding多态 Polymorphic Polymorphism多态性,迟绑定Late binding)重点在于对内存图的理解

       在执行期间(而非编译期间)判断所引用对象的实际类型,根据其实际的类型调用其相应的方法(方法都存放在 code seg,在执行期间使用)

       深层机制:在实际当中找方法的时候,在对象内部有一个方法的指针指向该方法,但是在new这个对象的时候,指针会根据新new的对象的不同而改变,指向新对象重写的方法,所以叫动态绑定(只有在运行期间,new出对象来,才能确定到底调用的是哪个方法,实际当中的地址,才会相应绑定到这个方法的地址上)。只要方法重写了,就会使用这种机制

       表面现象:对象作为父类身份传入参数,但是执行的却是自己重写的方法。

       Main函数中都是业务逻辑,表示功能的变化,相当于大管家,功能改变则必须变。业务方法,将结构设计好定义好,不需要变,如果以后想添加新的东西,继承父类,重写它的方法,搞定

       多态的存在,有三个必要条件:

       1)要有继承 2)要有重写 3)父类引用指向子类对象

       一旦满足,当调用父类当中被重写的方法时候,实际当中new的是哪个子类对象,就调用哪个子类对象重写的方法

 

18. abstract修饰抽象类,抽象方法。

       含有抽象方法的类(只有一个也算),必须声明为抽象类,抽象类必须被继承才能使用,所有的抽象方法必须全部被重写。

       抽象类不能被实例化。

       抽象方法只需声明,不需实现。

       配合多态,将那些总被重写,没必要实现的方法,写成抽象类,只有方法的声明,没有{类体},任何人不能修改类体。相当于C++中的虚函数,纯虚函数

       对于父类是抽象类型的子类,如果子类觉得自身不易实现父类的抽象方法,可以将自己也声明为抽象类,将方法还声明为抽象方法,让下一级子类去实现。实质是:抽象类被抽象类继承

       必须把父类中的所有抽象方法都实现么 必须全部重写!即便有些用不到。

       抽象类中,可以有非抽象方法么? 可以

 

19. final 可以用来修饰 —— 类(不能被继承)、方法(不能被重写)、变量(不能改变值)(成员变量,局部变量(形参)),相当于C++const关键字。

       使用final修饰的类有很多,不能被继承,更不能重写:java.lang.Stringjava.lang.Mathjava.lang.Boolean …

 

20. java只支持单继承,但是现实中存在着很多多继承的东西,用接口实现。使用implements关键词

       接口(interface)是抽象方法和常量值的定义的集合。本质上,接口是一种特殊的抽象类。定义一个接口时,interface替代class的位置。接口特征:

       1所有的方法全部默认public abstract的,没有{类体},也只能是public static的,却不用abstract关键字,public也可以省略。

       2所有的成员变量(不包括方法),即所有声明的属性,都默认public static final的,写不写作用一样,也只能是public static final的。

       3)只包含常量和方法的定义,没有变量和方法的实现

       4)接口可以多重实现,一个类可以实现多个接口,即类可以实现多继承

       5)接口可以继承其他的接口,并添加新的属性和抽象方法

       接口属性(成员变量)一定要定义成 public static final的原因:为了修正C++中多继承时容易出现问题的地方,多继承的多个父类之间,如果它们有相同的成员变量的时候,引用十分麻烦,而且运行时候会出现各种问题。接口的成员变量是static final的,只属于接口本身。

       1)多个无关的类,可以实现同一个接口

       2)一个类可以实现多个无关的接口

       3)与继承关系类似,接口与实现类之间存在多态性

       4)接口中的抽象方法,子类必须全部重写,除非子类也是抽象类

每一个接口暴露出实现这个接口的对象的一部分方法,与其他接口无关。对于多继承的对象,所继承的接口切换使用时,只需将对象强制转换成要使用的接口类型。

 

21. 同名的方法,仅仅是返回值不同,因为返回值可以不用,所以难以区分这两个方法。如果两个接口都含有同名的方法,仅仅是返回值不同,它们同时被一个类实现的时候,就会发生混乱,暂时无法解决!这种现象很少碰到。

 

22. 约定俗称的命名规则:

       1)类名的首字母大写

       2)变量名和方法名的首字母小写

       3)运用驼峰标识

 

第四章 异常处理

 

23. 异常:运行期出现的错误(除0溢出,数组下标越界,所要读取的文件不存在),观察错误的名字和行号最重要

       出现异常之后,java自动生成一个异常类对象(封装了异常事件的信息),并被提交给java运行时系统,这个过程称为抛出异常(throw);java运行时系统接收到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给其处理,这一过程称为捕获异常(catch)。

       Error是不可以处理的异常(动态连接失败、虚拟机错误等),Exception是可以处理的,RuntimeException是可以处理也可以不处理的

       Exception结构下:有些方法后直接用 throws注明可能出现的异常,实际当中用throw抛出,这类exception必须catch RuntimeException是经常出现的错误,系统自动检测并将它们交给缺省的异常处理程序(用户可不必对其处理)。

       getMessage()方法,用来得到有关异常事件的信息。

       PrintStackTrace()方法,用来跟踪异常事件发生时执行堆栈的内容

 

24. finally语句

       为异常处理提供一个统一的出口,使得在控制流程转到程序的其他部分之前,能够对程序的状态做统一的管理。无论try所指定的程序块中是否抛出例外,finally所指定的代码都要被执行。通常在finally语句中可以进行资源的清除工作(关闭打开的文件,删除临时文件)。

       调用有异常抛出的方法时候,应该try catch这种异常,如果处理不了,可以抛出,交给上一级调用者去处理。在main方法后写 throws Exception很省事,但这是不好的编程习惯,应该将异常try catch,这是程序员应该做的事情。

       还有一种方式,手动处理,先用throws声明可能出现的异常,再用throw关键词:throw new Exception(“….”);

       如果需要处理多个异常,先逮小的,再逮大的。

       要重写的方法抛出异常,那么重写的方法也必须抛出一样的异常,或者不抛异常。

 

第五章 数组

 

25. C/C++中的数组可以分配在栈空间上,但是java不能,因为java的数组是引用类型的。Java声明数组不能指定其长度,如:int a[5]; 这是错误的!正确格式为:int []a =new int[5]; java中所有new出来的东西都是分配在堆内存上。

       对于引用类型的数组,堆空间中存放的是指向数组的引用。内存图如下:

 

26. 动态初始化:数组先定义,再为数组元素分配空间和赋值。

       静态初始化:数组定义的同时,维数组元素分配空间并赋值。Int a[] = {1,2,3};

       数组分配空间后,每个元素按照成员变量的规则被隐式初始化。Boolean默认为false

 

27. main函数中数组参数(String [] args 使用命令行参数。在运行时,使用命令

java className参数1 参数2 参数n

       System.exit(-1);系统退出,当前虚拟机退出。-1表示非正常退出,0表示正常退出。在windows中看不出区别,-10都行

       dos环境下,乘号*有特殊含义,用字母x代替

       将字符串String类型转换成其他类型,例如:Double.parseDouble(stringName);

 

28. 选择排序算法(从上往下,从左往右比较)第一位与后面每一个比较,每次都使最小的置顶,第一位向后推进

       public static void selectSort(int [] a){

              int k,temp; //临时变量重复使用,算法加速

              for(int i = 0 ; i< a.length;i++){

                     k = i;

                     for(int j = k+1;j<a.length; j++){

                            if(a[k] > a[j]) k= j; //每次对比,一比到底,省去无意义的调换

                     }

                     if(k != i){

                            temp = a[i];

                            a[i] = a[k];

                            a[k] = temp;

                     }

              }

       }

 

29. year>date.year? 1 : (year < date.year ? -1 :( month > date.month ? -1 : (month <date.month ? -1 :(day > date.day ? 1 : (day < date.day ? -1 : 0))))); 这种写法执行速度快,但是程序可读性差。

       冒泡排序法:每次都从第一位向后滚动比较,每次使最大的沉底,最小的上升一次,最后一位向前推进

       public static void bubbleSort( Date[] days){

              int len = days.length;

              Date temp;

              for( int i = len-1 ; i >= 1 ;i--){

                     for(int j = 0; j < i;j++){

                            if(days[j].compare(days[j+1])> 0){

                                   temp =days[j+1];

                                   days[j+1] =days[j];

                                   days[j] =temp;

                            }

                     }

              }

       }

 

30. 作业:1. 用冒泡排序法 date类进行排序 2. 用冒泡排序法 int类型数组排序 3. 使用选择排序法 date类型数组排序 4. Count3Quit算法

 

31. 搜索算法

       一般先排序,如果无序,只能挨个搜索,效率极低。所以搜索之前先排序

       二分法搜索算法(折半查找):

       public static int binarySearch(int[]a ,int num){

       if (a.length == 0) {

           return-1;

       }

       intstartPosition = 0;

       int endPosition= a.length - 1;

       int midPosition= (startPosition + endPosition)/2;

       while(startPosition <= endPosition) {

           if(a[midPosition] == num) {

              returnmidPosition;

           }

           if(a[midPosition] > num ) {

              endPosition = midPosition - 1;

           }

           if(a[midPosition] < num ) {

              startPosition = midPosition + 1 ;

           }

           midPosition = (startPosition +endPosition)/2;

       }

       return-1;

    }

 

32. 二维数组(数组的数组)

     随着维数的增加,内存图像树状图一样延伸(而不是维度扩展)。

    数组的初始化:

数组的拷贝:使用java.lang.System类的静态方法

public static void arraycopy(Object src,int srcPos,Objectdest,

int destPos,int length)

    数组下标越界会抛出异常 IndexOutOfBoundsException

 

第六章 常用类

 

33. 对于String,只有new出来的才是对象,直接赋值的是字符串(存储于data seg)。String类已经重写了equals方法(比较对象内容)。

    String是不可变的字符序列;StringBuffer是可变的字符序列

    StringBuffer类中的 public StringBuffer replace(int start,

                            int end(不包括end所在的位置),

                            String str)

 

34. 包装类 封装了一个相应的基本数据类型数值,并为其提供了一系列操作

    long类型的数转换成Long类型对象:new Longlong value

    Long类型对象转换成long类型数:longValue(),intValue()

    String类型转换为int类型,Integer.parseInt(string);

 

35. Math 各种运算

    java.io.File    代表系统文件名(路径和文件名)

    路径符号:String directory = “dir1” + File.separator + “dir2”;

                            =“dir1/dir2”        = “dir1\\dir2”

    三种都可以,但是第三种只能在windows环境下使用,反斜杠’\’java中是转义字符,必须用’\\’才能表示路径分隔符,前两种在linux下也能使用

    如果class文件在包中,包名+文件名会被系统认为是文件名,所以路径是最上层包所在的路径。

 

36. java.lang.Enum类型 java1.5才有这种类型)使用enum关键字

    定义:public enum classname {red ,green, blue};

    使用:classname cn = classname.red;

 

第七章 容器(1136:一个图; 一个类Collections 三个知识点:增强forGeneticsAuto-boxing/unboxing;六个接口)

 

37. 一个图

Collection添加对象都是一个一个添加,其中,Set没有顺序不可重复,List有顺序可重复(两个对象互相equals);

Map都是成对添加。Map接口定义了存储“键(key)—值(value)映射对”的方法。

 

38. 比较对象是否相等,一般涉及到equals方法;equalshashCode方法必须同时重写。当对象用在Map接口中作为key(字典索引),涉及到hashCode方法,因为效率会更高。

 

39. 所有实现了Collection接口的容器类,都有一个iterator方法(Map没有),用于返回一个实现了Iterator接口的对象(父类引用指向子类对象)。

    使用Iterator遍历的时候,会将当前对象锁定,只有自己能使用,所以只能使用Iteratorremove方法处理当前对象,不能使用Collectionremove方法。

 

34. 增强型for循环:除了简单遍历并读出其中内容外,不建议使用。

    数组:不能方便的访问下标值。

    集合:与使用Iterator相比,不能方便的删除集合中的内容。(在内部也是调用Iterator

 

35. Set接口Collection的子接口,没有提供额外的方法,但实现Set接口的容器类中,元素无顺序不重复。J2SDK API 中提供的Set容器类有HashSetTreeSet

    List接口Collection的子接口,实现List接口的容器类中,元素有顺序可以重复。J2SKD 所提供的List容器类有 ArrayListLinkedList 等。

 

36. java.util.Collections ,提供了一些静态方法,实现了基于List容器的一些常用算法。

    所有可以“排序”的类,都实现了java.lang.Comparable接口Comparable接口中只有一个方法,public int compareTo(object obj);

    1. 返回0:相等;2. 返回正数:大于; 3. 返回负数:小于

 

37. Array读快改慢;Linked改快读慢;Hash两者之间。

    HashTableVector已经逐渐淘汰,因为它们内部是锁定的,读写效率都极低。

 

38. 实现Map接口的类,用来存储“键-值”对(名值对),通过键来标识,所以键值不能重复,通过查询hashcode来区分。Map接口的实现类有HashMapTreeMap(用二叉树实现)等。

 

39. JDK1.5之后。Auto-boxing/unboxing 在合适的时机自动打包、解包  自动将基础类型转换为对象;自动将对象转换为基础类型。

 

40. 泛型 Generics java泛型的底层与C++不太一样

    起因:JDK1.4以前类型不明确:装入集合的类型都被当做Object对待,从而失去自己的实际类型;从集合中取出时往往需要强制类型转换,效率低,容易产生错误。

    方案:在定义集合的时候,同时定义集合中对象的类型。

    好处:增强程序的可读性和稳定性。

    泛型与自动打包功能结合使用,程序更加简化。凡是用到集合的地方,尽量使用泛型。

可以在定义Collection的时候指定,也可以在循环时用Iterator指定,建议都指定。

 

第八章 IO

 

41. J2SDK 提供的所有流类型,位于包java.io内,都分别继承自以下四种抽象流类型

“读入写出”

字节流byte

字符流 两个字节

输入流

InputStream从文件进入程序

Reader从文件读出进入程序

输出流

OutputStream输出程序进入文件

Writer从程序写入文件

 

42. 问题:使用FileReader,汉字依然出现乱码

    BufferInputStreammark方法。

 

43.

缓冲流 Buffer

    转换流 InputStreamReader(将InputStream转换为Reader)和 OutputStreamWriter (将OutputStream转换为Writer

    数据流 DateInputStream DateOutputStream 分别继承自InputStreamOutputStream ,属于处理流,需要套接在InputStreamOutputStream类型的节点流上。提供了可以存取与机器无关的java原始类型数据(如:intdouble等)的方法

    Print PrintWriter PrintStream 都属于输出流,分别针对字符和字节。输出操作不会抛出异常,用户通过检测错误状态获取错误信息。有自动flush功能。提供了重载的printprintln方法用于多种数据类型的输出。

    Object

    序列化:将对象直接转换成字节流写到硬盘上或者网络上。序列化必用接口serializable。标记性接口,没有方法,做标记给编译器看,可以被序列化。

    transient关键字,修饰变量透明的,在序列化的时候不予考虑。

    externalizable接口  继承自serializable接口,可以自定义控制序列化过程

 

44. 系统默认编码格式GBKUTF-8比较省空间,常用于网络上传输

    System.in命令行键盘输入,阻塞进程,等待输入 

 

第九章 线程

 

45. 线程:一个程序内部的顺序控制流(一个程序中不同的执行路径)。机器中实际上运行的全都是线程。

    Main方法是主线程。

    进程:一个静态的概念,机器上的class文件、exe文件等。本身不能动,所谓进程的执行,是指进程里面主线程开始执行(main方法)开始执行

    DOS系统只支持单进程

 

46. 线程和进程的区别

    ①每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销

    ②线程可以看做轻量型的进程,同一类线程共享代码和数据空间。每个线程有独立的运行栈和程序计数器(PC),线程切换的开销小

    ③多进程:在操作系统中同时运行多个任务(程序)

    ④多线程:在同一应用程序中有多个顺序流同时执行

 

47. java的线程是通过java.lang.Thread类来实现的。VM启动时会有一个由主方法所定义的线程。可以通过创建Thread的实例来创建新的线程。每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体。通过调用Thread类的start()方法来启动一个线程。

 

48. 两种方法创建新的线程

    定义线程类实现 Runnable接口

    定义一个Thread的子类并重写其run()方法,然后生成该类的对象

 

49. sleep()调用者暂停若干毫秒

    join()调用者先执行完再给其他线程

    yield()调用者暂停,让给其他线程先执行

 

50. java提供一个线程调度器,按照线程的优先级决定调度哪个线程来执行,监控程序中启动后进入就绪状态的所有线程。

    优先级范围1-10,默认为5

 

51. synchronized 修饰方法,表示在执行这个方法的过程当中,锁定当前对象。而不是“同步方法”。

    Synchronized(this){}表示锁定当前对象

    对于锁定的对象(变量),其他未加锁的方法依然可以访问,其他加锁的方法不能访问

    互斥:加锁的方法,在某一时间段,保证只有一个线程进入到方法体中。不保证其他线程是否进入到另外一个方法中。

    主线程main中的方法,优先执行。(有待研究)

 

52.Object类的方法)wait() 使用后不再占有锁 ,需要notify()唤醒

    Thread类的方法)Sleep() 使用后仍然占有锁,睡一段时间后自己醒来

    只有使用了synchronized之后才有资格使用wait()方法

    this.wait();使当前的正在访问该对象的线程wait

    notify()叫醒一个正在该对象上wait的线程

java学习笔记

  • 2017年11月09日 13:53
  • 335KB
  • 下载

Java学习笔记(十六):UML类图符号以及各种关系

转自: UML类图符号 各种关系说明以及举例UML中描述对象和类之间相互关系的方式包括:依赖(Dependency),关联(Association),聚合(Aggregation),组合(Compo...

Java JDK 7学习笔记

  • 2017年11月16日 16:09
  • 13.47MB
  • 下载

java学习笔记

  • 2015年12月02日 21:08
  • 229KB
  • 下载

Java for Web学习笔记(九):Servlet(7)上传文件

上传文件 Servlet的参数设置 采用annotation方式如下: @WebServlet( name = "TicketServlet", urlPatterns = {"/tickets"...

java学习笔记

  • 2014年10月03日 10:39
  • 65KB
  • 下载

Java学习笔记之IO流

  • 2016年08月11日 07:36
  • 15KB
  • 下载

JAVA学习笔记16——Spring框架第三章

今天内容1. Spring框架的AOP之注解的方式 2. Spring框架的JDBC模板 3. Spring框架的事务管理 案例一:使用Spring框架的AOP技术对DAO层的功能进行增强案例一:使用...

java编程思想学习笔记

  • 2015年04月27日 16:13
  • 272KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:JAVA学习笔记
举报原因:
原因补充:

(最多只允许输入30个字)