Java练习题

Java的问答题。

一、 基本
1.一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制?

可以,限制:一个文件中只能有一个public类,并且此public类必须与文件名相同

2.在 JAVA 中如何跳出当前的多重嵌套循环?

使用break,让外层的循环条件表达式的结果可以受到里层循环体代码的控制

3.用最有效率的方法算出2乘以8等於几?

2<<3

4.简述逻辑操作(&,|,^)与条件操作(&&,||)的区别。

区别主要答两点: a.条件操作只能操作布尔型的,而逻辑操作不仅可以操作布尔型,而且可以操作数值型 b.逻辑操作不会产生短路

5.char型变量中能不能存贮一个中文汉字?为什么?

可以,因为Java中使用的编码是Unicode,一个char类型占2个字节(16比特),所以放一个中文是没问题的。

6.请说出作用域public,private,protected,以及不写时的区别?

作用域 当前类 同一package 子孙类 其他package public √ √ √ √ protected √ √ √ × friendly √ √ × × private √ × × ×

7.使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?

使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。

8.Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

Math.round(11.5)的结果为12,Math.round(-11.5)的结果为-11

9.是否可以从一个static方法内部发出对非static方法的调用?

不可以,因为非static方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用,而static方法调用时不需要创建对象,可以 直接调用。也就是说,当一个static方法被调用时,可能还没有创建任何实例对象,如果从一个static方法中发出对非static方法的调用,那个非static方法是关联到哪个对象上的呢?这个逻辑无法成立,所以,一个static方法内部发出对非static方法的调用。

10."=="和 equals 方法究竟有什么区别?

“==”是看两个对象是否是同一个对象,也就是两个[对象引用]是否指向同一个对象(Java分配的[内存地址]一样)当然如果用于int,long,double就不是看两个值是否相等了 equals()是比较两个对象的内容是否相等,一般如果用户自己不定义针对自己的类的equals()方法,那么就会使用Object你的类的父类的这个方法。如果你的类里没有[对象引用]的域,就不必要覆盖equals()(注意String域也是对象)String有自己的equals()方法,它已经覆盖了Object的该方法了。

11.Java里的传引用和传值的区别是什么?

在方法参数传递中当变量是8大基本数据类型的时候,就是传值,在方法里被修改了这个也不会影响 当变量是Object类型的时候,就是传引用

12.为什么Java里没有全局变量?

Global variables(全局变量) 是指可以全局访问的变量, Java不支持全局变量,原因如下: 1. 全局变量破坏了引用的透明性

13.如何将String类型转化成Number类型?

第一种方法:i=Integer.parseInt(s);//直接使用静态方法,不会产生多余的对象,但会抛出异常 第二种方法:i=Integer.valueOf(s).intValue();//Integer.valueOf(s) 相当于 new Integer(Integer.parseInt(s)),也会抛异常,但会多产生一个对象

二、 类相关
Final关键字有什么特点?

final:最终的意思,可以修饰类,方法和变量 它修饰的类,不能被继承 它修饰的方法,不能被重写 它修饰的变量,不能被改变

1.Integer与int的区别

Integer是int提供的封装类,而int是的基本数据类型; Integer默认值是null,而int默认值是0; 声明为Integer的变量需要实例化,而声明为int的变量不需要实例化; Integer是对象,用一个引用指向这个对象,而int是基本类型,直接存储数值。

2.如何将数值型字符转换为数字( Integer , Double )

1、如何将字符串String转化为整数int int i = Integer.parseInt(str); int i = Integer.valueOf(my_str).intValue(); 注: 字串转成Double, Float, Long的方法大同小异。 2、如何将字符串String转化为Integer Integer integer=Integer.valueOf(i) 3、如何将整数 int 转换成字串 String? String s = String.valueOf(i); String s = Integer.toString(i); String s = "" + i; 注:Double, Float, Long 转成字串的方法大同小异。

3.写clone()方法时,通常都有一行代码,是什么?

clone 有缺省行为,super.clone();因为首先要把父类中的成员复制到位,然后才是复制自己的成员。

4.抽象类的作用

1.通过继承它实现多态,后期绑定,可以为将来要实现的东西做好接口,实现重用性。 2.接口就是更纯粹的抽象类。

5.abstract class和interface有什么区别?

抽象类和接口的对比

Paste_Image.png

什么时候使用抽象类和接口
如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧。 如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。 如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。

6.abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?

都不可以,因为abstract申明的方法是要求子类去实现的,abstract只是告诉你有这样一个接口,你要去实现,至于你的具体实现可以是native和synchronized,也可以不是,抽象方法是不关心这些事的,所以写这两个是没有意义的。然后,static方法是不会被覆盖的,而abstract方法正是要子类去覆盖它,所以也是没有意义的。所以,总的来说,就是java语法不允许你这样做,事实上,也没有意义这样做。

7.接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)?抽象类中是否可以有静态的main方法?

接口可以继承接口。抽象类可以实现(implements)接口,抽象类是可以继承具体类。抽象类中可以有静态的main方法。 记住抽象类与普通类的唯一区别就是不能创建实例对象和允许有abstract方法。

9.如何取小数点前两位,并四舍五入。
BigDecimal k = new BigDecimal(25.9887);
BigDecimal j = k.setScale(2, BigDecimal.ROUND_HALF_UP);
String a= j.toString();
a = a.substring(a.length()-2);
System.out.println(a);
另一种思路:
double d = 3.1475926;
double d1 = d*100.0;
double d2 = Math.round(d1);
double d3 = d2/100.0;
System.out.println("d保留小数点2位并四舍五入的是:"+d3);
10.如何取得年月日,小时分秒?
public class DateTest {  
    public static void main(String[] args) throws ParseException {  
        Calendar now = Calendar.getInstance();  
        System.out.println("年: " + now.get(Calendar.YEAR));  
        System.out.println("月: " + (now.get(Calendar.MONTH) + 1) + "");  
        System.out.println("日: " + now.get(Calendar.DAY_OF_MONTH));  
        System.out.println("时: " + now.get(Calendar.HOUR_OF_DAY));  
        System.out.println("分: " + now.get(Calendar.MINUTE));  
        System.out.println("秒: " + now.get(Calendar.SECOND));  
        System.out.println("当前时间毫秒数:" + now.getTimeInMillis());  
        System.out.println(now.getTime());  
  
        Date d = new Date();  
        System.out.println(d);  
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
        String dateNowStr = sdf.format(d);  
        System.out.println("格式化后的日期:" + dateNowStr);  
          
        String str = "2012-1-13 17:26:33";  //要跟上面sdf定义的格式一样  
        Date today = sdf.parse(str);  
        System.out.println("字符串转成日期:" + today);  
    }  
} 
11.如何取得从 1970 年到现在的毫秒数
public static void main(String[] args) {
  // TODO Auto-generated method stub
  Date dt= new Date();
  Long time= dt.getTime();//这就是距离1970年1月1日0点0分0秒的毫秒数
  System.out.println(System.currentTimeMillis());//与上面的相同
 }
13.编码转换,怎样实现将 GB2312 编码的字符串转换为 ISO-8859-1 编码的字符串。
参考:https://zhidao.baidu.com/question/141886093.html
谨慎地使用getBytes(NAME_OF_CHARSET)和new String(bytes, NAME_OF_CHARSET),除非你很清楚的知道原始的字
符编码和传输协议使用的编码。

推荐使用基于服务器的配置、过滤器设置request/response的characterEncoding、content type属性。还有就是JSP页面的
pageEncoding属性、HTML meta元素的content type属性。尽量避免频繁的在代码中进行字符串转码,即降低了效率又增
加了风险。
14.String是最基本的数据类型吗?

不是,基本数据类型包括:byte,short,int,long,float,double,boolean,char. 而String是类代表字符串,属于引用类型,所谓引用类型包括:类,接口,数组...

15.是否可以继承String类?

String类是final类型的,故不可以继承。

16.String s = "Hello";s = s + " world!";这两行代码执行后,原始的String对象中的内容到底变了没有?

没有,s + " world!" 创建了一个新的对象。

17.String s = new String("xyz");创建了几个String Object? 二者之间有什么区别?

如果JVM常量池中存在"xyz",则是创建了一个对象s,如果不存在"xyz",则是先创建一个"xyz"对象,结果为2个对象

18.下面的代码有什么不妥之处?
  1. if(username.equals(“zxx”)){}
    直接调用equals方法可能会抛出NullPointerException异常。为了防止程序抛出异常在调用equals方法之前要先判断一下是否为空。 if( username!=null && username.equals(“zxx”){}这样写才完整。
  2. int x = 1;return x==1?true:false;
    ?true:false 多余了
20.String 和StringBuffer的区别

String 为不可变对象,一旦被创建,就不能修改它的值,StringBuffer是一个可变对象,当对他进行修改的时候不会像String那样重新建立对象,所以使用StringBuffer速度会比String 快。

21.StringBuffer与StringBuilder的区别

StringBuilder:线程非安全的 StringBuffer:线程安全的

22.如何把一段逗号分割的字符串转换成一个数组?
用正则表达式,代码大概为:String [] result = orgStr.split(“,”);
用 StingTokenizer ,代码为:
StringTokenizer  tokener = StringTokenizer(orgStr,”,”);
String [] result = new String[tokener.countTokens()];
Int i=0;
while(tokener.hasNext(){result[i++]=toker.nextToken();}
23.数组有没有length()这个方法? String有没有length()这个方法?

数组中没有length()这个方法,但是数组中有length这个属性。用来表示数组的长度 String中有length()这个方法。用来得到字符串的长度。

24.下面这条语句一共创建了多少个对象:String s="a"+"b"+"c"+"d";

javac 编译可以对 字符串常量直接相加的表达式进行优化, 不必要等到运行期去进行加法运算处理, 而是在编 译时去掉其中的加号, 直接将其编译成一个这些常量相连的结果。 题目中的第一行代码被编译器在编译时优化后, 相当于直接定义了一个”abcd”的字符串, 所以, 上面的代码应该只创建了一个 String 对象。

25.说出一些常用的类,包,接口,请各举5个

类: BufferedReader BufferedWriter String Integer Date 包: java.lang java.io java.util java.sql spring的包 接口: List Map Set Iterable Serializable

26.能不能自己写个类,也叫java.lang.String?

可以,但在应用的时候,需要用自己的类加载器去加载,否则,系统的类加载器永远只是去加载jre.jar包中的那个Java.lang.String。

三、 内部类
1.什么是内部类?Static Nested Class 和 Inner Class的不同。

Inner Class(内部类)定义在类中的类。 (一般是JAVA的说法) Nested Class(嵌套类)是静态(static)内部类。(一般是C++的说法) 静态内部类: 1 创建一个static内部类的对象,不需要一个外部类对象 2 不能从一个static内部类的一个对象访问一个外部类对象

2.内部类可以引用它的包含类的成员吗?有没有什么限制?

可以,但非静态内部类中不能定义静态成员(静态对象是默认加载,那么静态内部类应该先于外部类被加载到内存中)

3.一个房子里有椅子,椅子有腿和背,房子与椅子是什么关系,椅子与腿和背是什么关系?

has a is a

4.Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?

`
匿名内部类:
可以继承其他类,但不能用extends。
可以实现某接口,但不能用implements。

Paste_Image.png

答案来之知乎https://www.zhihu.com/question/21285716
`

四、 继承相关
1.super() 与 与 this() 的区别?

this是当前对象的引用,super是当前对象的父类对象的引用!

2.面向对象的特征有哪些方面

1.抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。抽象包括两个方面,一是过程抽象,二是[数据抽象]

2.继承:继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和[实例变量],并且类可以修改或增加新的方法使之更适合特殊的需要。

3.封装:封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。

4.多态性:多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多态性和包含多态性。多态性语言具有灵活、抽象、行为共享、[代码共享]的优势,很好的解决了应用程序函数同名问题。

3.java中实现多态的机制是什么?

java中实现多态的机制靠的是父类或者接口定义的引用变量可以指向子类或者具体的实现类的实例对象,而程序调的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。

4.jdk中哪些类是不能继承的?

final修饰的类

5.super.getClass()方法调用

getClass方法来自Object类,它返回对象在运行时的类型 如果想得到父类的名称,应该用如下代码: Java代码 getClass().getSuperClass().getName()

6.搞了多个重载方法,参数分别是int ,char,和double,然后将double x = 2,传递进去,会选择哪个方法?

调用参数为double的方法

7.构造器Constructor是否可被override?

其实你只需要记住一句话:构造器不是方法,那么用来修饰方法特性的所有修饰符都不能用来修饰构造器(并不等与构造器 具备这些特性,虽然不能用static修饰构造器,但它却有静态特性)构造器只能用 public private protected这 三个权限修饰符,且不能有返回语句。

8.Overload 和 Override 的区别。Overloaded 的方法是否可以改变返回值的类型?

方法的重写Overriding 和重载Overloading 是Java 多态性的不同表现。重写Overriding 是父类 与子类之间多态性的一种表现,重载Overloading 是一个类中多态性的一种表现。如果在子类中定义某 方法与其父类有相同的名称和参数,我们说该方法被重写(Overriding)。子类的对象使用这个方法时, 将调用子类中的定义,对它而言,父类中的定义如同被"屏蔽"了。如果在一个类中定义了多个同名的方法, 它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded 的方法 是可以改变返回值的类型

五、 异常的
1.try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?

会执行,在try语句中,在执行return语句时,要返回的结果已经准备好了,就在此时,程序转到finally执行了在转去之前,try中先把要返回的结果存放到不同于a的局部变量中去,执行完finally之后,在从中取出返回结果,因此,即使finally中对变量a进行了改变,但是不会影响返回结果。

2.final, finally, finalize的区别。

final --修饰符(关键字)。如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承 被final声明过的类也可以称为太监类(因为不能在继承)被final声明过的变量就变成常量了 如果加上static 就是全局常量了 finally—在异常!处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。 finalize —方法名。Java 技术允许使用finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。一旦垃圾回收器准备好释放对象占用的空间,将首先调用其finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。简单的说finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的

3.运行时异常与一般异常有何异同?

运行时异常和检查时异常。checked 异常就是经常遇到的IO异常,以及SQL异常等等,对于这种异常,编译器强制要求我们去try/catch。而对于runtime exception,我们可以不处理,比如:我们从来没有人去处理过NullPointerException异常,它就是运行时异常,这还是个最常见的异常之一哦。

4.error和exception有什么区别?

Error 是 Throwable 的子类,用于指示合理的应用程序不应该试图捕获的严重问题 Exception 类及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件

5.Java中的异常处理机制的简单原理和应用。

如果程序在运行中 发生了不允许的情况 比如 除0,比如空指针,常见的异常 [JVM])会自动的[抛出异常]不知道的异常,需要人工抛出 和捕获,当发生异常的时候捕获异常会对异常进行处理

6.请写出你最常见到的5个runtime exception。

NullPointerException、ArrayIndexOutOfBoundsException、ClassCastException。 StringIndexOutOfBoundsException WebServiceException ArithmeticException(整数除0时发生)

7.JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try块中可以抛出异常吗?

throws是获取异常 throw是抛出异常 try是将会发生异常的语句括起来,从而进行异常的处理 catch是如果有异常就会执行他里面的语句 而finally不论是否有异常都会进行执行的语句。 throw和throws的详细区别如下: throw是语句抛出一个异常。 语法:throw (异常对象); throw e; throws是方法可能抛出异常的声明。(用在声明方法时,表示该方法可能要抛出异常) 语法:[(修饰符)](返回值类型)(方法名)([参数列表])[throws(异常类)]{......} public void doA(int a) throws Exception1,Exception3{......}
举例: 如: void doA(int a) throws Exception1,Exception3{ try{ ...... }catch(Exception1 e){ throw e; }catch(Exception2 e){ System.out.println("出错了!"); } if(a!=b) throw new Exception3("自定义异常"); }

六、 线程的
1.同步和异步有何异同,在什么情况下分别使用他们?举例说明。

1.同步交互:指发送一个请求,需要等待返回,然后才能够发送下一个请求,有个等待过程 2.异步交互:指发送一个请求,不需要等待返回,随时可以再发送下一个请求,即不需要等待。 区别:一个需要等待,一个不需要等待,在部分情况下,我们的项目开发中都会优先选择不需要等待的异步交互方式。 哪些情况建议使用同步交互呢?比如银行的转账系统,对数据库的保存操作等等,都会使用同步交互操作,其余情况都优先使用异步交互。

2.线程的基本概念、线程的基本状态以及状态之间的关系

`
1.什么是线程
一个线程是进程的一个顺序执行流。同类的多个线程共享一块内存空间和一组系统资源,线程本身有一个供程序执行时的堆栈。线程在切换时负荷小,因此,线程也被称为轻负荷进程。一个进程中可以包含多个线程。
2.进程与线程的区别
一个进程至少有一个线程。线程的划分尺度小于进程,使得多线程程序的并发性高。另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程的区别在于每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但[操作系统]并没有将多个线程看做多个独立的应用来实现进程的调度和管理以及资源分配。
3.并发原理
多个线程或进程”同时”运行只是我们感官上的一种表现。事实上进程和线程是并发运行的,OS的线程调度机制将时间划分为很多时间片段(时间片),尽可能均匀分配给正在运行的程序,获取CPU时间片的线程或进程得以被执行,其他则等待。而CPU则在这些进程或线程上来回切换运行。微观上所有进程和线程是走走停停的,宏观上都在运行,这种都运行的现象叫并发,但是不是绝对意义上的“同时发生。
4.线程状态

Paste_Image.png
1.新建

用new语句创建的线程对象处于新建状态,此时它和其他[Java]对象一样,仅被分配了内存。

2.等待

当线程在new之后,并且在调用start方法前,线程处于等待状态。

3.就绪

当一个线程对象创建后,其他线程调用它的start()方法,该线程就进入就绪状态。处于这个状态的线程位于Java虚拟机的可运行池中,等待cpu的使用权。

4.运行状态

处于这个状态的线程占用CPU,执行程序代码。在并发运行环境中,如果计算机只有一个CPU,那么任何时刻只会有一个线程处于这个状态。
只有处于就绪状态的线程才有机会转到运行状态。

5.阻塞状态

阻塞状态是指线程因为某些原因放弃CPU,暂时停止运行。当线程处于阻塞状态时,Java虚拟机不会给线程分配CPU,直到线程重新进入就绪状态,它才会有机会获得运行状态。
阻塞状态分为三种:
1、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
2、同步阻塞:运行的线程在获取对象同步锁时,若该同步锁被别的线程占用,则JVM会把线程放入锁池中。
3、其他阻塞:运行的线程执行Sleep()方法,或者发出I/O请求时,JVM会把线程设为阻塞状态。当Sleep()状态超时、或者I/O处理完毕时,线程重新转入就绪状态。

6.死亡状态

当线程执行完run()方法中的代码,或者遇到了未捕获的异常,就会退出run()方法,此时就进入死亡状态,该线程结束生命周期。
`

3.启动一个线程是用run()还是start()?

start()

4.java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用?

有两种实现方法,分别是继承Thread类与实现Runnable接口 用synchronized关键字修饰同步方法

5.sleep() 和 wait() 有什么区别?

先说wait,wait的本质是条件等待,这里涉及到了锁的概念(也就是多线程中要保证[线程安全]的锁)。所谓条件等待就是已经获得了锁的线程,由于需要满足某种条件才能继续执行,而当前不满足条件,所以只能等待。所以调用wait的一个前提条件就是要先拿到锁。拿到锁的线程,wait之后,该线程就进入条件[等待队列],并且释放锁,让其他线程执行。当其他线程的执行使得条件满足之后,再调用notify或者notifyAll方法,将条件[等待队列]中的线程唤醒,这些线程再去请求锁,拿到锁的线程接着去执行。 sleep(long t)的意思是暂停当前线程t[毫秒],当然,其他线程就得到了时间片,sleep与线程是否获得锁无关。调用sleep线程进入TimeWaiting状态。

7.多线程有几种实现方法?同步有几种实现方法?

多线程实现:继承Thread类,重写run();实现Runnable接口,重写run(); 同步方式:synchronized修饰,wait(),notify()

8.当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?

1.其他方法前是否加了synchronized关键字,如果没加,则能。 2.如果这个方法内部调用了wait,则可以进入其他synchronized方法。 3.如果其他个方法都加了synchronized关键字,并且内部没有调用wait,则不能。 如果其他方法也被static关键字修饰,那么这些方法使用的同步锁(或者可以叫做监视器)是当前对象“类锁“,而不是当前“对象锁”(“对象”是“类”的具体实),所以用的是两个锁,就不能同步。

9.简述synchronized和java.util.concurrent.locks.Lock的异同 ?

1.Lock能完成几乎所有synchronized的功能,并有一些后者不具备的功能,如锁投票、定时锁等候、可中断锁等候等 2.synchronized 是[Java](http://lib.csdn.net/base/javase) 语言层面的,是内置的关键字;Lock 则是JDK 5中出现的一个包,在使用时,synchronized 同步的代码块可以由JVM自动释放;Lock 需要程序员在finally块中手工释放,如果不释放,可能会引起难以预料的后果(在多线程环境中)。

10.线程如何同步和通讯
多线程同步示例,来自《疯狂java讲义》。
通过synchronized,wait(),notify(),notifyAll()实现多线程同步与通信
例:
假设现在系统中有两个线程,这两个线程分别代表存钱者和取钱者---现在假设系统有一种特殊的要求,系统要求存款者和取钱者不断地重复存钱、取钱动作,而且要求每当存款着将钱存入指定账户后,取钱者就立即取出这笔钱。不允许存款者连续两次存钱,也不允许取钱者连续两次取钱。
程序中,通过一个旗标flag标识,本次账户操作是不是存款操作,以便下次操作可以探测


1.Account账户类,有取钱(drawBalance)和存钱(deposit)两个同步方法
package com.sunchp;
public class Account {
    private String accountNo;
    private double balance;
 
    private boolean flag = false;
 
    public Account(String _accountNo, double _balance) {
        this.accountNo = _accountNo;
        this.balance = _balance;
    }
 
    public String getAccountNo() {
        return accountNo;
    }
 
    public void setAccountNo(String accountNo) {
        this.accountNo = accountNo;
    }
 
    public double getBalance() {
        return balance;
    }
 
    public synchronized void drawBalance(double drawBalance) {
        if (flag) {
            if (balance > drawBalance) {
                System.out.println(Thread.currentThread().getName() + "取钱成功,正在吐钞:" + drawBalance);
                balance -= drawBalance;
                flag = false;
                this.notifyAll();
                System.out.println(Thread.currentThread().getName() + "余额为:" + getBalance());
            } else {
                System.out.println(Thread.currentThread().getName() + "取钱失败,余额不足");
            }
        } else {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
 
    public synchronized void deposit(double depositBalance) {
        if (flag) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println(Thread.currentThread().getName() + " 存款:" + depositBalance);
            this.balance += depositBalance;
            flag = true;
            this.notifyAll();
            System.out.println(Thread.currentThread().getName() + "余额为:" + getBalance());
        }
    }
}
2.取钱线程类
package com.sunchp;
 
public class MyThread1 implements Runnable {
    private Account account;
    private double drawBalance;
 
    public Account getAccount() {
        return account;
    }
 
    public void setAccount(Account account) {
        this.account = account;
    }
 
    public double getDrawBalance() {
        return drawBalance;
    }
 
    public void setDrawBalance(double drawBalance) {
        this.drawBalance = drawBalance;
    }
 
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            account.drawBalance(drawBalance);
        }
    }
}
3.存钱线程类
package com.sunchp;
 
public class MyThread2 implements Runnable {
    private Account account;
    private double depositBalance;
 
    public Account getAccount() {
        return account;
    }
 
    public void setAccount(Account account) {
        this.account = account;
    }
 
    public double getDepositBalance() {
        return depositBalance;
    }
 
    public void setDepositBalance(double depositBalance) {
        this.depositBalance = depositBalance;
    }
 
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            account.deposit(depositBalance);
        }
    }
}
4.测试类,main方法
package com.sunchp;
 
public class Test {
 
    public static void main(String[] args) throws Exception {
        Account acc = new Account("001", 1000);
 
        MyThread1 mt1 = new MyThread1();
        mt1.setAccount(acc);
        mt1.setDrawBalance(20);
 
        Thread t1 = new Thread(mt1, "取钱者1");
        Thread t2 = new Thread(mt1, "取钱者2");
 
        MyThread2 mt2 = new MyThread2();
        mt2.setAccount(acc);
        mt2.setDepositBalance(20);
 
        Thread t3 = new Thread(mt2, "存钱者1");
        Thread t4 = new Thread(mt2, "存钱者2");
 
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}
七、 集合的
1.介绍Collection框架的结构

常用容器继承关系图

Paste_Image.png

Iterator不是容器,只是一个操作遍历集合的方法

  1. Collection和Map
    Collection:
    是容器继承关系中的顶层接口。是一组对象元素组。有些容器允许重复元素有的不允许,有些有序有些无序。 JDK不直接提供对于这个接口的实现,但是提供继承与该接口的子接口比如 List Set。
    Map:
    一个保存键值映射的对象。 映射Map中不能包含重复的key,每一个key最多对应一个value。
    List和Set:
    他们2个是继承Collection的子接口,就是说他们也都是负责存储单个元素的容器。
    最大的区别如下:
    List是存储的元素容器是有个有序的可以索引到元素的容器,并且里面的元素可以重复。
    Set里面和List最大的区别是Set里面的元素对象不可重复。
    详细:http://www.jianshu.com/p/46f2c704abeb
2.Collection框架中实现比较要实现什么接口

要实现 comparable 接口,把你的自定义类实现以上接口,实现 compareTo 方法

3.Collection 和 Collections的区别。

Collection是集合类的上级接口,继承与他有关的接口主要有List和Set Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全等

4.你所知道的集合类都有哪些?主要方法?

map:Hashmap,Treemap set: Hashset Treeset list: Arraylist LinkedList 主要方法:add() clear() remove size() isEmpty() iterator()等

6.List、Map、Set三个接口,存取元素时,各有什么特点?

list是线性表,元素是你任意加进去的。 map是[key-value]二元映射表,可做索引。 set是集合表,元素不重复。

7.List 和 Map 区别?

list是对象集合,允许对象重复。 map是键值对的集合,不允许key重复。

8.hashCode方法的作用?

也就是说 List 是一个有序的、可重复的对象容器接口,Set是一个无序的、不可重复的对象容器接口 。后面都讲了 Set 是如何实现不重复的 :为了避免多次重复的使用 equal 方法带来的系统负担 ,set 首先调用hashCode 方法来检测 是否被占用 如果被占用 然后调用 equal 方法判断被占用的是否相同

10.说出ArrayList,Vector, LinkedList的存储性能和特性

ArrayList 采用的是数组形式来保存对象的,这种方式将对象放在连续的位置中,所以最大的缺点就是插入删除时非常麻烦 LinkedList 采用的将对象存放在独立的空间中,而且在每个空间中还保存下一个链接的索引 但是缺点就是查找非常麻烦 要丛第一个索引开始 ArrayList和Vector都是用数组方式存储数据,此数组元素数要大于实际的存储空间以便进行元素增加和插入操作,他们都允许直接用序号索引元素,但是插入数据元素涉及到元素移动等内存操作,所以索引数据快而插入数据慢. Vector使用了sychronized方法(线程安全),所以在性能上比ArrayList要差些. LinkedList使用双向链表方式存储数据,按序号索引数据需要前向或后向遍历数据,所以索引数据慢,是插入数据时只需要记录前后项即可,所以插入的速度快.

12.Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?

==是用来判断两者是否是同一对象(同一事物),而equals是用来判断是否引用同一个对象。还是对象的引用。根据Java的存储机制可知,set里面存放的是对象的引用,所以当两个元素只要满足了equals()时就已经指向同一个对象,也就出现了重复元素。所以应该用equals()来判断。

13.HashMap和Hashtable的区别

1.HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行)。 2.HashMap是非synchronized,而Hashtable是synchronized,这意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。 3.另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。 3.由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。 HashMap不能保证随着时间的推移Map中的元素次序是不变的。

14.两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?

不对,如果两个对象x和y满足x.equals(y) == true,它们的哈希码(hash code)应当相同。Java对于eqauls方法和hashCode方法是这样规定的:(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;(2)如果两个对象的hashCode相同,它们并不一定相同。当然,你未必要按照要求去做,但是如果你违背了上述原则就会发现在使用容器时,相同的对象可以出现在Set集合中,同时增加新元素的效率会大大下降(对于使用哈希存储的系统,如果哈希码频繁的冲突将会造成存取性能急剧下降)。

15.TreeSet里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的compareTo方法,还是使用的子类的compareTo方法,还是抛异常!

如果子类和父类都复写了compareTo方法那么各自调用自己的compareTo方法 如果子类没有复写compareTo方法,那么调用的都是父类的compareTo方法

八、 io 的语法
1.什么是java序列化,如何实现java序列化?或者请解释Serializable接口的作用。

将一个java对象变成字节流的形式传出去或者从一个字节流中恢复成一个java对象,序列化是将对象状态转换为可保持或传输的格式的过程。 什么是java序列化,如何实现java序列化?或者请解释Serializable接口的作用 将一个java对象变成字节流的形式传出去或者从一个字节流中恢复成一个java对象 序列化是将对象状态转换为可保持或传输的格式的过程。 java中的序列化机制能够将一个实例对象(只序列化对象的属性值,而不会去序列化什么所谓的方法。)的状态信息写入到一个字节流中使其可以通过socket进行传输、或者持久化到存储数据库或文件系统中;然后在需要的时候通过字节流中的信息来重构一个相同的对象。一般而言,要使得一个类可以序列化,只需简单实现java.io.Serializable接口即可。 序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。

2.序列化接口的id有什么用?

序列化时为了保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。

3.java中有几种类型的流?JDK为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类?

IO流四大家族: InputStream:输入字节流。 OutputStream:输出字节流。 Reader:输入字符流。 Writer:输出字符流。

4.字节流与字符流的区别

https://www.zhihu.com/question/39262026 总而言之,一切都是字节流,其实没有字符流这个东西。字符只是根据编码集对字节流翻译之后的产物。

九、虚拟机方面的语法
1.什么是类的反射射机制?

反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

2.类的反射机制中的包及核心类?

java.lang.reflect这个包下面的类 Constructor 提供关于类的单个构造方法的信息以及对它的[访问权限] Field 提供有关类或接口的单个字段的信息,以及对它的动态[访问权限]。 Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。 Modifier 类提供了 static 方法和常量,对类和成员访问修饰符进行解码。 Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。

3.得到 Class 的三个过程是什么?

对象.getClass() 类.class或Integer.type(int) Integer.class(java.lang.Integer) Class.forName();

4.描述一下JVM加载class文件的原理机制?

JVM中类的装载是由类加载器(ClassLoader)和它的子类来实现的,Java中的类加载器是一个重要的Java运行时系统组件,它负责在运行时查找和装入类文件中的类。 由于Java的跨平台性,经过编译的Java源程序并不是一个可执行程序,而是一个或多个类文件。当Java程序需要使用某个类时,JVM会确保这个类已经被加载、连接(验证、准备和解析)和初始化。类的加载是指把类的.class文件中的数据读入到内存中,通常是创建一个字节数组读入.class文件,然后产生与所加载类对应的Class对象。加载完成后,Class对象还不完整,所以此时的类还不可用。当类被加载后就进入连接阶段,这一阶段包括验证、准备(为静态变量分配内存并设置默认的初始值)和解析(将符号引用替换为直接引用)三个步骤。最后JVM对类进行初始化,包括:1)如果类存在直接的父类并且这个类还没有被初始化,那么就先初始化父类;2)如果类中存在初始化语句,就依次执行这些初始化语句。    类的加载是由类加载器完成的,类加载器包括:根加载器(BootStrap)、扩展加载器(Extension)、系统加载器(System)和用户自定义类加载器(java.lang.ClassLoader的子类)。 2(JDK 1.2)开始,类加载过程采取了父亲委托机制(PDM)。PDM更好的保证了Java平台的安全性,在该机制中,JVM自带的Bootstrap是根加载器,其他的加载器都有且仅有一个父类加载器。类的加载首先请求父类加载器加载,父类加载器无能为力时才由其子类加载器自行加载。JVM不会向Java程序提供对Bootstrap的引用。下面是关于几个类加载器的说明: Bootstrap:一般用本地代码实现,负责加载JVM基础核心类库(rt.jar);   Extension:从java.ext.dirs系统属性所指定的目录中加载类库,它的父加载器是Bootstrap;   System:又叫应用类加载器,其父类是Extension。它是应用最广泛的类加载器。它从环境变量classpath或者系统属性java.class.path所指定的目录中记载类,是用户自定义加载器的默认父加载器。

5.heap和stack有什么区别。
6.java的事件委托机制和垃圾回收机制
7.GC是什么? 为什么要有GC?
8.垃圾回收的优点和原理。并考虑2种回收机制。
9.垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?
10.什么时候用assert。
11.java中会存在内存泄漏吗,请简单描述。

Java的编程练习题。

一、基础
1.如何取小数点前两位,并四舍五入。
2.设计出计算任意正整数的阶层
3.任意数字序列“123456”之类,输出它们所有的排列组合
4.判断身份证:要么是15位,要么是18位,最后一位可以为字母,并写程序提出其中的年月日。
5.现在输入n个数字,以逗号,分开;然后可选择升或者降序排序;按提交键就在另一页面显示按什么排序,结果为,提供reset
二、数组(排序,选择)
1.有数组a[n],用java代码将数组元素顺序颠倒
2.排序都有哪几种方法?请列举。用JAVA实现一个快速排序。
3.一列数的规则如下: 1、1、2、3、5、8、13、21、34...... 求第30位数是多少, 用递归算法实现。
4.给定一个有序的数组,如果往该数组中存储一个元素,并保证这个数组还是有序的,那么这个元素的存储角标位如何获取
5.打印出九九乘法表
6.打印出三角形
7.打印数组,元素间用逗号隔开,例:[0],[1]
8.获取数组的最大值和最小值
9.给定数组排序,递增,冒泡
10.1~100之间 7的倍数的个数。并打印。
11.3000米长的绳子,每天减一半。问多少天这个绳子会小于5米?不考虑小数
12.打印一个矩形
13.获取1到10 10个数的和。
三、字符串
1.如何将数字转换为字符?
2.如何把一段逗号分割的字符串转换成一个数组?
3.有一个字符串,其中包含中文字符、英文字符和数字字符,请统计和打印出各个字符的个数。
4.编写一个函数将一个十六进制数的字符串参数转换成整数返回
5.编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串,但要保证汉字不被截取半个,如“我ABC”,4,应该截取“我AB”,输入“我ABC汉DEF”,6,应该输出“我ABC”,而不是“我ABC+汉的半个”。
6.将字符串反转
7.获取一个字符串在另一个字符串中出现的次数
8.给定一个字符数组。按照字典顺序从小到大排序
9.一个字符串在整串中出现的次数
10.两个字符串中最大相同的字串
11.模拟一个trim功能一致的方法
四、io
1.文件读写,实现一个计数器
2.写一个程序,从文件(c:\test.txt)中查出字符串”mobnet”出现的次数?
3.编写一个程序,将a.txt文件中的单词与b.txt文件中的单词交替合并到c.txt文件中,a.txt文件中的单词用回车符分隔,b.txt文件中用回车或空格进行分隔。
4.读入文件信息,根据分隔符,存入字符串数组words中
5.编写一个程序,将 d: \ java 目录下的所有.java 文件复制到d: \ jad 目录下,并 将原来文件的扩展名从.java 改为.jad
五、集合
1.ArrayList如何实现插入的数据按自定义的方式有序存放
2.请写出一段代码获取结构List<Map<String,String>>中的各个Map的键值,并通过System.out.pringln()打印出来。
六、线程
1.设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。
2.子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序。
3.有类似的这样一串"abcddeffx.asre-321"!assra.."请实现以下方法将该字符串中的各个字符串出现的次数统计出来
七、类相关
1.如何取得年月日,小时分秒?
2.如何取得从 1970 年到现在的毫秒数
3.如何格式化日期?
4.编码转换,怎样实现将 GB2312 编码的字符串转换为 ISO-8859-1 编码的字符串。
5.判断第二个日期比第一个日期大
八、设计模式
1.几种单例模式
题目补充
2.写一段代码获取结构 List<Map<String,String>>中各个Map,并通过System.out.println()打印出来(15)

/**

  • 将指定的 结构为 List<Map<String,String>>的参数 通过System.out.println()打印出来
  • 格式:"键名:键值"
  • @param List<Map<String,String>>

*/

3.有类似这样的一串字符"abcddeffx.asre-321!assra..",请实现以下方法将字符串各个字符的出现的次数统计出来

/**

  • 将指定的 结构为 List<Map<String,String>>的参数 通过System.out.println()打印出来
  • 格式:"键名:键值"
  • @param List<Map<String,String>>
  • @return Map<字符,出现的次数>
    */
    public Map<Character,Integer> staticCharcnt(String str){

}

4.在一个文本文件(文件大小不超过2k)中存放了很多以空格分隔的英语单词,请写一段伪代码或用文字描述来实现,已得到没有重复的、且按字典顺序排序的所有单词(20分)
5.请用javascript语言解析如下json对象,取出对象中所有数据或将其显示在页面上。(15)
6.在项目中一导入jquery1.7库,请实现用jquery查找下列表格的第二行第三列的值。(15)
7.写一个程序,从文件(c:\test.txt)中查出字符串”mobnet”出现的次数?
8.编写一个程序,将a.txt文件中的单词与b.txt文件中的单词交替合并到c.txt文件中,a.txt文件中的单词用回车符分隔,b.txt文件中用回车或空格进行分隔。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,562评论 18 399
  • (一)Java部分 1、列举出JAVA中6个比较常用的包【天威诚信面试题】 【参考答案】 java.lang;ja...
    独云阅读 7,064评论 0 62
  • 转自:http://blog.csdn.net/jackfrued/article/details/4492194...
    王帅199207阅读 8,495评论 3 93
  • 一、创建线程的两种方式: 1、创建 java.lang.Thread 类的子类,重写该类的 run方 法 a、Th...
    冰凡513阅读 191评论 0 0
  • 亲爱的宝,今天妈妈刚刚看完学校对初中最后一周的安排,心生颇多感触!你小时候、幼儿园、小学,以及现在三年的初中生活各...
    半亩方塘_阅读 504评论 0 0