Think in java小练整理(1)

Chapter 3:

1、检查对象是否相等:

package c03;

/**Thinking In Java example program.
 * @author WangCan
 * @2019-02-13
 * */
public class Number {
   public static void main(String[] args){
       Integer n1=new Integer(47);
       Integer n2=new Integer(47);
       System.out.println(n1==n2);  // n1不等于n2,因为对象的内容相同,句柄却是不同的
       System.out.println(n1!=n2);
   }
}

小结:尽管对象的内容相同,句柄却是不同的,而 ==和!=比较的正好就是对象句柄。所以输出结果实际上先是 false,再是 true。

若想比较两个对象的实际内容是否相同,就要使用equals()方法(注意这个方法不适用于“主类型”的数据):

public class EqualsMethod {
 public static void main(String[] args) {
 Integer n1 = new Integer(47);
 Integer n2 = new Integer(47);
 System.out.println(n1.equals(n2));
 }
} 

正如我们预计的那样,此时得到的结果是 true。但是假设您创建了自己的类,就象下面这样:

package c03;

/**The first Thinking In Java example program.
 * @author WangCan
 * @2019-02-13
 * */

    class Value{
        int i;
    }
public class Number {
   public static void main(String[] args){
       Value v1=new Value();
       Value v2=new Value();
       v1.i=v2.i=100;
       System.out.println(v1.equals(v2));

       System.out.println(v1==v2);  
       System.out.println(v1!=v2);
   }
}

此时的结果又变回了false、false、true!这是由于 equals()的默认行为是比较句柄。所以除非在自己的新类中改变了 equals(),否则不可能表现出我们希望的行为。

2、输出二进制的方法:

1)、int类型转换二进制:

static void pBinInt(String s, int i) {
        System.out.println(
                s + ", int: " + i + ", binary: ");
        System.out.print(" ");
        for(int j = 31; j >=0; j--)
            if(((1 << j) & i) != 0)
                System.out.print("1"); //int类型的数据输出二进制
            else
                System.out.print("0");
        System.out.println();
    }

2)、long类型转换二进制:

static void pBinLong(String s, long l) {
        System.out.println(
                s + ", long: " + l + ", binary: ");
        System.out.print(" ");
        for(int i = 63; i >=0; i--)
            if(((1L << i) & l) != 0)
                System.out.print("1");
            else
                System.out.print("0");
        System.out.println();
    }

 以上的方法可以直接在主函数中用pBinInt("string类型数值", int类型数值)和pBinLong("string类型数值",long类型数值)进行调用。

具体应用:

public class Number {
    static void pBinInt(String s, int i) {
        System.out.println(
                s + ", int: " + i + ", binary: ");
        System.out.print(" ");
        for(int j = 31; j >=0; j--)      //int转换输出二进制
            if(((1 << j) & i) != 0)
                System.out.print("1");    
            else
                System.out.print("0");
        System.out.println();
    }
    static void pBinLong(String s, long l) {
        System.out.println(
                s + ", long: " + l + ", binary: ");
        System.out.print(" ");
        for(int i = 63; i >=0; i--)      //long转换输出二进制
            if(((1L << i) & l) != 0)
                System.out.print("1");
            else
                System.out.print("0");
        System.out.println();
    }

    public static void main(String[] args){
        Random rand =new Random();
        int i=rand.nextInt();
        int j=rand.nextInt();
        pBinInt("-1",-1);
        pBinInt("+1",+1);
        int maxpos = 2147483647;
        pBinInt("maxpos", maxpos);
        int maxneg = -2147483648;
        pBinInt("maxneg", maxneg);
        pBinInt("i", i);
        pBinInt("~i", ~i);
        pBinInt("-i", -i);
        pBinInt("j", j);
        pBinInt("i & j", i & j);
        pBinInt("i | j", i | j);
        pBinInt("i ^ j", i ^ j);
        pBinInt("i << 5", i << 5);
        pBinInt("i >> 5", i >> 5);
        pBinInt("(~i) >> 5", (~i) >> 5);
        pBinInt("i >>> 5", i >>> 5);
        pBinInt("(~i) >>> 5", (~i) >>> 5);
        long l = rand.nextLong();
        long m = rand.nextLong();
        pBinLong("-1L", -1L);
        pBinLong("+1L", +1L);
        long ll = 9223372036854775807L;
        pBinLong("maxpos", ll);
        long lln = -9223372036854775808L;
        pBinLong("maxneg", lln);
        pBinLong("l", l);
        pBinLong("~l", ~l);
        pBinLong("-l", -l);
        pBinLong("m", m);
        pBinLong("l & m", l & m);
        pBinLong("l | m", l | m);
        pBinLong("l ^ m", l ^ m);
        pBinLong("l << 5", l << 5);
        pBinLong("l >> 5", l >> 5);
        pBinLong("(~l) >> 5", (~l) >> 5);
        pBinLong("l >>> 5", l >>> 5);
        pBinLong("(~l) >>> 5", (~l) >>> 5);
  }
}

3、循环的中断与连续:

可用break 和continue 控制循环的流程。其中,break 用于强行退出循环, 不执行循环中剩余的语句。而 continue 则停止执行当前的循环,然后退回循环起始位置,开始新的反复。

循环中插入标签label时,break和continue会中断当前循环,回到label标签存在的地方。label标签需要紧靠在循环之前, 中间插入任何语句都是不明智的:

label1:    //label标签使用
外部循环{
  内部循环{
    break;           //1:中断内部循环,并在外部循环结束
    continue;        //2:移回内部循环的起始处
    continue label1; //3:却同时中断内部循环以及外部循环,并移至label1 处。随后,它实际是继续循环,但却从外部循环开始
    break label1;    //4:会中断所有循环,并回到 label1 处,但并不重新进入循环,而是完全终止了两个循环
   }
}
public class Number {
    public static void main(String[] args) {
        int i = 0;
        outer:       //外部标签
        for (; true; ) {
            inner:   //内部标签
            for (; i < 10; i++) {
                prt("i=" + i);
                if (i == 2) {
                    prt("continue");
                    continue;
                }
                if (i == 3) {
                    prt("break");
                    i++;   //否则i永远不会增加
                    break;
                }
                if (i == 7) {
                    prt("continue outer");
                    i++;   //否则i永远不会增加
                    continue outer;
                }
                if (i == 8) {
                    prt("break outer");
                    break outer;
                }
                for (int k = 0; k < 5; k++) {
                    if (k == 3) {
                        prt("continue inner");
                        continue inner;
                    }
                }
            }
        }
    }
    static void prt(String s){
        System.out.println(s);
    }
}

如果没有break outer 语句,就没有办法在一个内部循环里找到出外部循环的路径。这是由于break本身只能中断最内层的循环(对于continue 同样如此)。 当然,若想在中断循环的同时退出方法,简单地用一个return 即可。

用Switch判断随机生成的字母是元音还是辅音字母:

public class Number {
    public static void main(String[] args) {
        for(int i = 0; i < 100; i++) {
            char c = (char)(Math.random() * 26 + 'a');   //随机生成字母
            System.out.print(c + ": ");
            switch(c) {
                case 'a':
                case 'e':
                case 'i':
                case 'o':
                case 'u':
                    System.out.println("vowel");
                    break;
                case 'y':
                case 'w':
                    System.out.println(
                            "Sometimes a vowel");
                    break;
                default:
                    System.out.println("consonant");
            }
        }
    }
}

尽管我们在这儿表面上要处理的是字符,但switch 语句实际使用的字符的整数值。在 case 语句中,用单引 号封闭起来的字符也会产生整数值,以便我们进行比较。

Math.random()会产生0到1之间的一个值,所以只需将其乘以想获得的最大随机数(对于英语字母,这个数字是 26),再加上一个偏移量,得到最小的随机数。多个条件输出相同的结果时可以向上面那样放在一起判断。

这里我们需要特别注意的是:

Math.random()会产生一个 double 值,所以 26 会转换成double 类型,以便执行乘法运算。这个运算也会产生一个 double 值。这意味着为了执行加法,必须先将'a'转换成一个 double类型的数,再利用一个类型的强制转换(char),double 结果会转换回 char。 我们的问题是,(char)会作什么样的处理呢?换言之,假设一个值是29.7,我们把它转换成一 个char,那么结果值到底是 30 还是29 呢?答案可从下面这个例子中得到:

public class CastingNumbers {
 public static void main(String[] args) {
 double above = 0.7,below = 0.4;
 System.out.println("above: " + above);   
 System.out.println("below: " + below);   
 System.out.println("(int)above: " + (int)above);       //结果为above=0
 System.out.println("(int)below: " + (int)below);       //结果为below=0
 System.out.println("(char)('a' + above): " +(char)('a' + above));    
                                                        //结果为(char)('a' + above):a     
 System.out.println("(char)('a' + below): " +(char)('a' + below));         
                                                        //结果为(char)('a' + below):a     
 }
} 

也就是说将一个 float 或 double 值造型成整数值后,总是将小数部分“砍掉”,不作任何进位处理。 

4、用构建函数(构造器)自动初始化:

对于构建器的创建,可将其想象成为自己写的每个类都调用一次 initialize()。我们在命名构建器的时候应该使构建器的名字与类名相同。若某个类有一个构建函数(构造器),那么在创建对象时,Java 会自动调用那个构建器。

class Rock {
 Rock(int i) {   //构建器:方法名与类名完全相同
 System.out.println("Creating Rock number " + i);
 }
}
public class SimpleConstructor {
 public static void main(String[] args) {
 for(int i = 0; i < 10; i++)
 new Rock(i);
 }
}

 构建函数属于一种较特殊的方法类型,因为它没有返回值。这与 void 返回值存在着明显的区别。对于void 返 回值,尽管方法本身不会自动返回什么,但仍然可以让它返回另一些东西。构造函数则不同,它不仅什么也不 会自动返回,而且根本不能有任何选择。若存在一个返回值,而且假设我们可以自行选择返回内容,那么编 译器多少要知道如何对那个返回值作什么样的处理。

由于构建函数的名字由类名决定,所以只能有一个 构建函数名称。但假若我们想用多种方式创建一个对象呢?例如,假设我们想创建一个类,令其用标准方式进行初始化,另外从文件里读取信息来初始化。此时,我们就需要两个构建函数,一个没有自变量(默认构建器),另一个将字串作为自变量——用于初始化对象的那个文件的名字。由于都是构建函数,所以它们必须有相同的名字即类名。所以为了让相同的方法名伴随不同的自变量类型使用,“方法重载”是非常关键的 一项措施。同时,尽管方法重载是构建函数必需的,但它亦可应用于其他任何方法,且用法非常方便。

区分多个重载方法的简单的规则:每个重载的方法都必 须采取独一无二的自变量类型列表。

public class Overloading{
        static void print(String s,int i){
            System.out.println("String:"+s+",int:"+i);
        }
        static void print(int i,String s){
            System.out.println("int:"+i+",String:"+s);
        }
        public static void main(String[] args){
            print("String first",11);
            print(99,"int first");
        }
}

若创建一个没有构 建器的类,则编译程序会帮我们自动创建一个默认构建器:

class Bird {
 int i;
}
public class DefaultConstructor {
 public static void main(String[] args) {
 Bird nc = new Bird();    //new Bird()作用是新建一个对象,并调用默认构建器
 }
}

5、this关键字:

假定我们在一个方法的内部,并希望获得当前对象的句柄。由于那个句柄是由编译器“秘密”传递的,所以没有标识符可用。然而,针对这一目的有个专用的关键字:this。this 关键字(注意只能在方法内部使用) 可为已调用了其方法的那个对象生成相应的句柄。可像对待其他任何对象句柄一样对待这个句柄。

public class Leaf{
    private int i=0;
    Leaf increment(){
        i++;
        return this;  //在方法内部获得当前对象的句柄
    }
    void print(){
        System.out.println("i="+i);
    }
    public static void main(String[] args){
        Leaf x=new Leaf();
        x.increment().increment().increment().print();
    }

}

理解了 this 关键字后,我们可更完整地理解 static(静态)方法的含义。它意味着一个特定的方法没有 this。我们不可从一个 static 方法内部发出对非 static 方法的调用,反过来说是可以的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值