J2SE中的一些概念性问题

  前几天跟朋友讨论了几个问题,不算大事,都是一些细节方面的,但正是由于一些概念性的东西不清楚,导致无法做出判断,面试

题中也有可能会出现,我总结了一下,写了几个小代码加注释,方便自己以后查阅

 

1.字符编码问题

 

/*
 * 我们知道Java中一个字符占2个字节,而我们又知道字符串是由字符系列组合而成,那我们
 * 可不可以理解一个字符串的字节数 = 字符的个数(字符串的长度) * 2 呢?
 * 下面的代码将证实这个问题
 */
public class CodeTest {

 public static void main(String[] args) {
  
  String ch = "A";  //等效于 char ch = 'A'
  String str = "abc";
  String strSub = "abc中国";
  System.out.println(ch.getBytes().length);
  System.out.println(str.getBytes().length);
  System.out.println(strSub.getBytes().length);//此处打印结果为7,推测出字母占1字节,汉字占2字节,这个很像GB2312码表?
  
  /*
   * 上面的代码测试字符和字符串的字节数问题,但好像与我们所想的有差别,其实不然
   * 我们都知道Java是采用Unicode码表的,到底是怎么一回事呢?
   * 我们在写一个.java文件时,编译器编译成.class文件,这个过程是需要用到Unicode码表的
   * 这时我们说char类型占2字节,字符串=字符*2,这样是成立的
   * 但当JVM运行时,调用getBytes,这个是解码过程了,解码当然也需要一个码表了,这时候就默认当前系统的码表来解码了
   * 这个问题曾今困惑我好长时间,今天终于知道了,虽然不是什么大问题,但也要了解额
   */
 }
}

 

 

2.作用域的问题
其实这类问题以前还真没重视过,毕竟遇到的都是些小虾小蟹,直到前些天碰到一个面试题,才发觉有必要重视,代码如下:

 

public class StringBuilderTest {

 public static void main(String[] args) {
  StringBuilder sb1 = new StringBuilder("aaa");
  StringBuilder sb2 = new StringBuilder("bbb");
  
  run(sb1, sb2);
  
  //下面的代码并不等效于run方法哦
  //sb1.append("111");
  //sb2 = sb1;
  
  System.out.println(sb1);
  System.out.println(sb2);
 }
 
 public static void run(StringBuilder sb1, StringBuilder sb2) {
  sb1.append("111");
  sb2 = sb1;
 }
}


/*
 * 这个是典型的作用域的问题
 * 如上代码,当我们操作对象时(改变对象的内容),其作用域不会局限于方法体,而变量的作用域仅仅在方法内部
 */

 

 


3.继承的关系
在学面向对象的时候,其实还是有些概念性的东西没有弄清的,其实那也是必然,因为当时不知道自己究竟不知道什么,所以有些问

题就没有暴露出来,好在现在遇到了

 

/*
 * 1.此程序是为了测试当子类重写了父类的方法(run)时,用父类类型的变量obj来指向new出的子类对象,
 * 问obj调用的run方法是哪个类的
 *
 * 2.我们在父类的构造方法中调用一下run方法,那当我们new子类的对象时,问程序如何执行
 */

 

public class OverrideMehod {

 public static void main(String[] args) {
  
  A obj = new B();  //new出B的对象时调用父类的构造方法,根据打印结果,我们可以得出,此处是调用子类的

run方法
  System.out.println("----------------------");
  
  obj.run();//动态绑定,即当用父类类型的变量指向子类对象时,调用的run方法是子类的重写方法
  System.out.println(obj.name);//静态绑定,即当用父类类型的变量指向子类对象时,调用的name成员变量是

父类的
  
  //obj不可调用子类的runner方法
 }

}

 

class A {
 
 public String name = "A";
 
 public A() {
  
  run();
  
  //根据前面的测试结果,我们可以很肯定的说出,当我们new子类对象时,此处的this代表的是子类的对象
  System.out.println(this);
 }
 
 public void run() {
  System.out.println("this is A");
 }
}

class B extends A {
 
 public String name = "B";
 
 public B() {
  super();  //此处的super是隐藏的
 }
 
 public void run() {
  System.out.println("this is B");
 }
 
 public void runner() {
  System.out.println("this is runner!!");
 }
}

 

 

4.静态代码块和类加载机制的相关问题
static其他的一些用法我就不提了,在这主要是关于静态代码块的,父类和子类均有静态代码块,当new子类对象时,程序的执行顺

序如何,看代码证实了这个问题,看看注释

 

/* 类的加载机制:
 * 加载一个类时,会优先去找父类的加载器,然后父类在去找父类的加载器,一级级向上寻找,如果super的加载器可以加载,
 * 那么就加载,如果不行,就一级级向下推,直到此类本身,这就是Java中的委托机制
 * 所以下面的代码会优先执行父类中的静态代码块
 * 另外,当一个子类new对象时,"必然"会调用父类的构造方法,即在子类的构造方法中肯定含有super,不管是隐式还是显式的
 * 如果是隐式的,即父类肯定含有隐式的构造方法,即无参
 * 但如果父类只有一个有参的构造方法,子类也只有有参的构造方法(这时子类肯定不会有无参的构造方法,因为父类么有无

参,super()调用不了),
 * 那么在子类的构造方法的第一行必须显式的调用父类的构造方法 即super(实参);
 * 否则编译器会报错,如下代码可以试验一下
 *
 */

public class StaticTest {

 public static void main(String[] args) {
  
  new BBB("111");
 }
}

class AAA {
 
 static {
  System.out.println("this is AAA...");
 }
 
 public AAA() {
  System.out.println("this is constructor of AAA...");
 }
 
 public AAA(String name) {
  System.out.println("this is constructor of AAAA...");
 }
}

class BBB extends AAA {
 
 static {
  System.out.println("this is BBB...");
 }
 
 public BBB() {
  //super();  隐藏的
  System.out.println("this is constructor of BBB...");
 }
 
 public BBB(String name) {
  System.out.println("this is constructor of BBBB...");
 }
}

你可能感兴趣的:(J2SE中的一些概念性问题)