Thinking in java 笔记

本文深入讲解Java中的核心概念,包括继承、多态、内部类、枚举、异常处理、I/O操作、网络编程及反射机制等,通过实例解析Java语言的关键特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

继承与动态绑定

向上转型与向下转型

类内属性的初始化

static关键字

java中的两同类之间的对象进行 = ,将和&操作相同,就是别名,都指向同一个对象。

异或运算符实现swap

位移运算符

使用位移运算符和异或运算符进行的加法

使用&运算符的计算含有多少个1

在构建器中调用构建器

final 与static final

初始化的继承

向上溯形的必要性

覆盖与过载

内部类

继承的初始化

abstract 与interface的区别

枚举的使用

HashTable 复写hashCode(), equals()

违例差错控制

java的IO

java 中的 lambda表达式写法

java反射机制

网络编程(Socket 套接字)


继承与动态绑定

父类的方法可以在沿着继承链中的子类中多次重写,JVM决定运行时的调用方法,这就是动态绑定

public class InheritTest {
    public void showMe(){
        System.out.println( " father " );
    }
    
    public static void main(String args[]){
        InheritTest i = new InheritTest();
        i.showMe();

        i = new InheritTest1();
        i.showMe();

        i = new InheritTest2();
        i.showMe();

        i = new InheritTest3();
        i.showMe();
    }
}
public class InheritTest1 extends InheritTest{
    public void showMe() {
        System.out.println( " son " );
    }
}
public class InheritTest2 extends InheritTest1 {
    public void showMe() {
        System.out.println( " grandson " );
    }
}
public class InheritTest3 extends InheritTest2{
    public void showMe() {
        System.out.println( " grandson'son " );
    }
}

//输出的结果为
 father 
 son 
 grandson 
 grandson'son 

向上转型与向下转型

向上转型是,本身的方法会丢失

public class Animal {
    public void eat(){
        System.out.println( "eat ...." );
    }

    public static void main(String args[]){
        Animal a = new Animal();
        a.eat();
        a = new Cat();
        a.eat();
        a = new Dog();
        a.eat();

    }
}
public class Cat extends Animal {
    public void eat(){
        System.out.println( "eat fish" );
    }
}
public class Dog extends Animal {

    public void eat() {
       System.out.println( "eat shit" );
    }

    public void run(){
        System.out.println( "four legs" );
    }
}
结果///
eat ....
eat fish
eat shit

此时向上转型为Animal,继承类的单独的方法 run() 方法丢失。

向下转型

 public static void main(String args[]){
      Animal a = new Cat();
      Cat c = (Cat) a;
      c.eat();

      Dog d = (Dog) a;
      d.eat();
    }

输出
eat fish
"main" java.lang.ClassCastException: com.weixy.think.extend.Cat cannot be cast to com.weixy.think.extend.Dog

因为对象a本来就是由Cat转化而成的,可以转化为本身,而Cat并不能转为Dog.  如果是单纯的向下转换也是会报错的

 public static void main(String args[]){
      Animal a = new Animal();
      Cat c = (Cat) a;
      c.eat();
    }

经典的多态问题分析

public class VirtualExtends {
    static class A {
        public String show(D obj) {
            return ("A and D");
        }

        public String show(A obj) {
            return ("A and A");
        }

    }

    static class B extends A{
        public String show(B obj){//独有的方法
            return ("B and B");
        }

        public String show(A obj){//重写
            return ("B and A");
        }
    }

    static class C extends B{

    }

    static class D extends B{

    }
    public static void main(String args[]){
        A a1 = new A();
        A a2 = new B();
        B b = new B();
        C c = new C();
        D d = new D();

        System.out.println("1--" + a1.show(b));//A  A  B可以向上转型成A
        System.out.println("2--" + a1.show(c));//A  A  C也可以转换为A
        System.out.println("3--" + a1.show(d));//A  D  直接调用show(D obj)方法

        //a2是由B向上转型成A。
        // 其中a2的方法有B中的  show(A obj) ,因为是重写的父类方法
        //            有A中的  show(D obj)

        System.out.println("4--" + a2.show(b));//B  A
        System.out.println("5--" + a2.show(c));//B  A
        System.out.println("6--" + a2.show(d));//A  D

        //b中的方法有B中的  show(A obj), show(B obj)  以及A中继承得到的show(D obj)
        System.out.println("7--" + b.show(b)); //B  B
        System.out.println("8--" + b.show(c)); //B  B
        System.out.println("9--" + b.show(d)); //A  D
    }
}

以上参考博客 :   Sharember 的博客

类内属性的初始化

public class ClassInit {

    boolean bo;
    char c;
    byte b;
    short s;
    int i;
    long l;
    float f;
    double d;
    String str;

    public static void main(String args[]){
        ClassInit c = new ClassInit();
        int i =0;
    }
}
//默认初始化数值
 bo = false
 c = '\u0000' 0
 b = 0
 s = 0
 i = 0
 l = 0
 f = 0.0
 d = 0.0
 str = null

static关键字

被static修饰的对象内部的成员,该成员是静态变量,只能存在一个i,占用的是同一个内存,尽管下面的创建个两个对象,但是

这两个对象共享同一个i,

public class StaticTest {
    static int i =47;
    int num ;
    public StaticTest(int num){
        this.num = num;
    }
    public static void main(String args[]){
        StaticTest s1 = new StaticTest(1);
        StaticTest s2 = new StaticTest(2);
        System.out.println( s1.i );
        System.out.println( s2.i );

        s1.i = 48;
        
        System.out.println( s1.i );
        System.out.println( s2.i );
    }
}

//打印结果
47
47
48
48

静态代码区

public class StaticTest {
    static {
        System.out.println( "我是静态代码块" );
    }
    static int i =47;
    int num ;
    public StaticTest(int num){
        this.num = num;
    }

    static void show(){
        System.out.println( "我是静态方法" );
    }
    public static void main(String args[]){
         StaticTest  s = new StaticTest ();
        s.show();
    }
}
//打印结果
我是静态代码块
我是静态方法

静态代码区运行在对象初始化之前

静态引入包

在同一个package下创建两个class (不在一个包下会报错),这样就可以直接使用引入包类的静态方法。

/***  PrintHelper .java  ***/
package com.weixy.think.extend;

public class PrintHelper {
    public static void print(Object obj){
        System.out.println( obj );
    }
}

/***  ImportTest .java  ***/
package com.weixy.think.extend;

import static com.weixy.think.extend.PrintHelper.print;

public class ImportTest {
    public static void main(String args[]){
        print("test");

    }

}

四种static的用法:

1.static修饰类中的成员变量    多个对象之间共享该成员

2.static修饰l类中的方法,不需要初始化该类就可以调用方法

3.static代码块。在该类初始化之前就运行区域类的方法

4.静态导包,将类的方法直接导入到类中,使用时不需要再添加类名

第一个java程序(查看编译环境)

public class getPeoperty {
    public static void main(String[] args) {
        Properties p = System.getProperties();
        p.list( System.out);//打印配置列表
        System.out.println( "use page" );
        Runtime rt = Runtime.getRuntime();
        System.out.println("totalMemory:" +rt.totalMemory()+"  ,freeMemory"+rt.freeMemory() );
        try {
            Thread.currentThread().sleep( 5 * 1000);
        } catch(InterruptedException e) {
        }
    }
}

java中的两同类之间的对象进行 = ,将和&操作相同,就是别名,都指向同一个对象。

public class Number {
    int i;

    public static void main(String[] args) {
        Number i1 = new Number();
        i1.i = 7;
        Number i2 = new Number();
        i2.i = 49;
        i1 = i2;

        i1 = i2; // & 别名操作,哈哈
        System.out.println( "i1.i:"+i1.i+",i2.i:"+i2.i );

        i1.i = 6;
        System.out.println( "i1.i:"+i1.i+",i2.i:"+i2.i );
    }
}

//输出
i1.i:49,i2.i:49
i1.i:6,i2.i:6

//java没有赋值构造函数,不能重载运算符
class Letter {   
       char c; 
} 
 
public class PassObject {   

    static void f(Letter y){
     y.c = 'z';   
}   

public static void main(String[] args) { 
    Letter x = new Letter();     
    x.c = 'a';     
    System.out.println("1: x.c: " + x.c);     
    f(x);     
    System.out.println("2: x.c: " + x.c);   
    } 
} 
//这里是因为对象传址。。。句柄,对对象的引用。。

异或运算符实现swap

可以通过数组传递进行传址操作,或者封装成对象,对象传句柄,对对象的引用,也可以解决传址的问题

public class WeiyiSign {

    public static void main(String[] args) {

        //将整形转化为二进制二点字符串
        int b = 7;
        String bBinary = Integer.toBinaryString( b );

        int x = new Integer( 8 );
        int y = new Integer( 9 );
        
        
        //无效,因为传值,非引用传递
        swap(x,y);
        
        int temp = x^y;
        x = x^temp;
        y = y^temp;
        int j = 0;
        
    }

    //swap,传入的不是引用
    public static void swap(int x,int y){
        int temp = x^y;
        x = x^temp;
        y = y^temp;
    }
}

位移运算符

>> ,在正数右移的时候补0,负数右移的时候补1,

>>>无论正负在右移的时候补0

public class MoveSign {

    public static void main(String[] args) {
        int x = 7;
        String x1 = Integer.toBinaryString( x );
        System.out.println("x1: "+x1);
        x = x>>1;
        String x2 = Integer.toBinaryString( x );
        System.out.println("x2: "+x2);
        
        int y = -7;
        String y1 = Integer.toBinaryString( y );
        System.out.println("y1: "+y1);
        y = y>>1;
        String y2 = Integer.toBinaryString( y );
        System.out.println("y2: "+y2);
    }
}
//打印结果
x1: 111
x2: 11
y1: 11111111111111111111111111111001
y2: 11111111111111111111111111111100

使用位移运算符和异或运算符进行的加法

public static void main(String[] args) {

      int a = 7;
      int b = 9;
      int temp = a^b;

      while(b!=0) {
          int x = a ^ b;//不考虑进位的加法
          int y = (a & b) << 1;//考虑是否存在进位。若存在进位,左移一位并再做加法
          a = x;
          b = y;
      }
    }

使用&运算符的计算含有多少个1

  public static void main(String[] args) {
        int num = 25;
        int count =0;
        System.out.println(Integer.toBinaryString( num ));
        while(num!=0){
            num = num&(num-1);
            count++;
        }
        System.out.println(count);
    }

在构建器中调用构建器

public class MoveSign {
    private int num;
    private String str;
    MoveSign(){

    }
    MoveSign(int num){
        this.num = num;
    }
    MoveSign(String str){
        this.str = str;
    }
    MoveSign(int num ,String str){
        this( num);//只能调用一个,不能调用第二个
        this.str = str;
    }
    public static void main(String[] args) {
        
    }
}

final 与static final

final 可以修饰类,方法,局部变量。

对于基本类型的添加final修饰,final会将其变成一个常数,不能再修改,但是当fina修饰的是对象的时候,这个时候句柄是常数,不能在改变句柄,但是对象本身是可以修改的。同理数组也同样可以被修改,因为数组也是传句柄的(传址)。

当final 修饰的是方法时,该方法不能再被子类覆盖和重写。

当final修饰的是对象,类时,这个类不能被继承。

被static final 修饰的属性表示不能修改,并且可以通过类名访问。final修饰的属性表示是一个常量。

初始化的继承

public class Insert {
    int i = 9;
    int j;

    public Insert() {
        prt( "i = " + i + ", j = " + j );
        j = 39;
    }

    static int x1 = prt( "static Insect.x1 initialized" );
    static int prt(String s) {
        System.out.println( s );
        return 47;
    }
}
public class Beetle extends Insert {
    int k = prt("Beetle.k initialized");
    Beetle() {
        prt("k = " + k);
        prt("j = " + j);
    }
    static int x2 =     prt("static Beetle.x2 initialized");//在创建对象之前就进行初始化

    static int prt(String s) {
        System.out.println(s);
        return 63;
    }

    public static void main(String[] args) {
        int i=0;
        prt("Beetle constructor");
        Beetle b = new Beetle();
    }
}
输出结果
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
i = 9, j = 0
Beetle.k initialized
k = 63
j = 39

在继承关系的类初始化之前,是由基类到派生类的顺序进行初始化顺序的,静态成员和方法在对象初始化之前完成,同样按照由基类到派生类的顺序。java语言中不手动析构对象,但是在析构的过程中,顺序是由派生类到基类。继承类的对象初始化之前线初始化基类,基类初始化完成之后才会初始化继承类的对象。


向上溯形的必要性

public class Note {
    private int value;

    private Note(int val) { value = val; }

    public static final Note
    middleC = new Note(0),
    cSharp = new Note(1),
    cFlat = new Note(2);  .
}
    
public class Instrument {
    public void play(Note n) {
        System.out.println("Instrument.play()");
    }
}

public class Wind  extends Instrument {
    public void play(Note n) {
        System.out.println( "Wind.play()" );
    }
}
public class Music {

    public static void tune(Instrument i) {
        i.play(Note.middleC);
    }

    public static void main(String[] args) {
        Wind flute = new Wind();
//play方法已经被继承类重写。所以向上转型时,取得这个对象句柄,并将其作为基础类型句柄使用
        tune(flute);
    }
}

覆盖与过载

class NoteX {   
public static final int     MIDDLE_C = 0, C_SHARP = 1, C_FLAT = 2; 
} 
 
class InstrumentX { 
  public void play(int NoteX) {    
      System.out.println("InstrumentX.play()");   
  } 
} 
 
class WindX extends InstrumentX {
   // OOPS! Changes the method interface:  
 public void play(NoteX n) {     
    System.out.println("WindX.play(NoteX n)");   
 } 
} 
 
public class WindError {
    public static void tune(InstrumentX i) {    
         // ...     
        i.play(NoteX.MIDDLE_C);   
    }   
    public static void main(String[] args) {     
        WindX flute = new WindX();     
        tune(flute); // Not the desired behavior!   
    } 
}
输出是基类方法的调用
InstrumentX.play()

基类和继承类都有play方法,InstrumentX 中的参数是int型,而继承类WindXplay()方法的参数是NodeX类,继承类中的方法虽然和基类方法名称相同,但是并没有重载基类中的play()方法。

内部类

abstract public class Contents {
    abstract public int value();
}
public interface Destination {
    String readLabel();
}
public class Parcel3 {

    private class PContents extends Contents {
        private int i = 11;

        public int value() {
            return i;
        }
    }

    protected class PDestination       implements Destination {
        private String label;
        private PDestination(String whereTo) {       label = whereTo;     }
        public String readLabel() { return label; }
    }

    public Destination dest(String s) {     return new PDestination(s);   }
    public Contents cont() {      return new PContents();    }

}
public class Test {
    public static void main(String[] args) {
        Parcel3 p = new Parcel3();
        Contents c = p.cont();
        Destination d = p.dest("Tanzania");
    }
}
PDestination类和PContents类是Parcel3的内部类,且是private,protected属性的,
PContents是private的,除了Parcel3都不能访问,
PDestination是protected的,除了Parcel3、Parcel3的内部类、以及继承类可见。

在作用域内的类

public interface Contents {
    int value();
}
public interface Destination {
    String readLabel();
}
public class Parcel4 {

    public Destination dest(String s) {
        class PDestination         implements Destination {//方法内部类
            private String label;
            private PDestination(String whereTo) {
                label = whereTo;
            }
            public String readLabel() { return label; }

        }
        return new PDestination(s);
    }

 public static void main(String[] args) {
        Parcel4 p = new Parcel4();     
        Destination d = p.dest("Tanzania");
    }
}

PDestination是Parcel4方法dest中的一个类,返回的是一个上溯造型Destination的句柄。PDestination位于dest的作用于,而不是在Parcel4的部分。Parcel4只是提供了一个方法,构建PDestination(s)返回一个指向Destination的句柄。

public interface Contents {
    int value();
}

public class Parcel6 {
    public Contents cont() {
        return new Contents() {
            private int i = 11;
            public int value() {
                return i; }
            }; 
    }

    public static void main(String[] args) {
        Parcel6 p = new Parcel6();
        Contents c = p.cont();
    }
}

cont方法返回的是接口Contents,return new Contents(){} ,创建出Contents衍生出的一个匿名类ide对象。返回的是一个自动上溯造型成Contents的句柄。

public class Parcel7 {

    public Wrapping wrap(int x) {
         return new Wrapping(x) {
             public int value() {
                 return super.value() * 47;
             }
         };
    }
    public static void main(String[] args) {
        Parcel7 p = new Parcel7();
        Wrapping w = p.wrap( 10 );
        int i=0;
        int j = w.value();
    }
}

wrap方法创建了一个继承Wrapping的匿名继承类,value()方法被重写。

public interface Destination {
    String readLabel();
}
public class Parcel8 {
    public Destination dest(final String dest) {
        return new Destination() {
            private String label = dest;
            public String readLabel() { return label; }
        };
    }

    public static void main(String[] args) {
        Parcel8 p = new Parcel8();
        Destination d = p.dest( "Tanzania" );
    }
}

dest方法返回了一个继承Destination的匿名类,因为匿名类,不能拥有自己的构建器,但是可以通过上述方法进行初始化。

 内部类的覆盖

public class Egg {
    protected class Yolk {
        public Yolk() {
            System.out.println( "Egg.Yolk()" );
        }
    }

    private Yolk y;
    public Egg() {
        System.out.println("New Egg()");
        y = new Yolk();
    }

}
public class BigEgg extends Egg {

    Yolk y;
    public class Yolk {
        public Yolk() {
            System.out.println("BigEgg.Yolk()");
        }
    }
    public BigEgg(){
        System.out.println("new.BigEgg()");
        y = new Yolk();
    }

    public static void main(String[] args) {
        BigEgg b = new BigEgg();
        int i = 0 ;
    }
}
//输出
New Egg()
Egg.Yolk()
new.BigEgg()
BigEgg.Yolk()

并没有覆盖。虽然在BigEgg创建了一个同样名为Yolk()的类,但是作用域不相同, 并没有被覆盖。一个是BigEgg.y,另一个则是Egg.y。若想让BigEgg中的Yolk继承Egg中的Yolk.可以显示指定继承。class Yolk extends Egg.Yolk。

继承的初始化

public abstract class Glyph {
    Glyph(){
        System.out.println("Glyph  before construct");
        draw();
        System.out.println("Glyph  after  construct");
    }

    abstract void draw();
}
public class GlyphControler extends Glyph {
    int val = 1;

    GlyphControler(int i){
        System.out.println("GlyphControler before contruct");
        this.val = i;
        draw();
        System.out.println("GlyphControler after  contruct");
    }

    void draw() {
        System.out.println("GlyphControler draw val = " + val);
    }

    public static void main(String[] args) {
        GlyphControler g = new GlyphControler( 5 );
    }
}
//输出
Glyph  before construct
GlyphControler draw val = 0
Glyph  after  construct
GlyphControler before contruct
GlyphControler draw val = 5
GlyphControler after  contruct

构造的顺序为基类到继承类,但是抽象类的draw方法调用的是覆盖后的方法,但是初始却不是1;

(1) 在采取其他任何操作之前,为对象分配的存储空间初始化成二进制零。

(2) 就象前面叙述的那样,调用基础类构建器。此时,被覆盖的draw()方法会得到调用(的确是在 RoundGlyph构建器调用之前),此时会发现 radius的值为 0,这是由于步骤(1)造成的。

(3) 按照原先声明的顺序调用成员初始化代码。

(4) 调用衍生类构建器的主体

abstract 与interface的区别

1.抽象类可以有构造方法,接口中不能有构造方法。

2.抽象类中可以有普通成员变量,接口中没有普通成员变量

3.抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。

4. 抽象类中的抽象方法的访问类型可以是public,protecte,但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。

5. 抽象类中可以包含静态方法,接口中不能包含静态方法

6. 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型。

7. 一个类可以实现多个接口,但只能继承一个抽象类。

摘自 __Meng的博客

枚举的使用

public class Abqh {
    int i ;

    public Abqh(int i) {
        this.i = i;
    }

    @Override
    public String toString() {
        return "Abqh{" +
                "i=" + i +
                '}';
    }
}
public class EnumTest {
    static void print(Enumeration e){
        while(e.hasMoreElements()){
            System.out.println( e.nextElement().toString() );
        }
    }
    public static void main(String[] args) {
        Vector vec = new Vector(  );
        for(int i = 0;i<10;i++){
            vec.add( new Abqh( i ) );
        }
        Enumeration e = vec.elements();//转换乘枚举
        print( e );
    }
}

//
Abqh{i=0}
Abqh{i=1}
Abqh{i=2}
Abqh{i=3}
Abqh{i=4}
Abqh{i=5}
Abqh{i=6}
Abqh{i=7}
Abqh{i=8}
Abqh{i=9}
public enum enumTest2 {
    RED("red",1) ,GAREEN("green" , 2),WHITE("white",3);

    private String color;
    private  int index;

    enumTest2(String color,int index) {
        this.color = color;
        this.index = index;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public static void main(String[] args) {
        System.out.println(RED.color);
        System.out.println(RED.getIndex());
    }
}

枚举的类型中,在没有使用枚举类型时,与普通的类型没有区别,使用枚举类型提供的选项后,就是使用了枚举的模板类型构建常数数据结构。

HashTable 复写hashCode(), equals()

public class HashBean {
    int  num ;

    public HashBean(int num) {
        this.num = num;
    }

    @Override
    public int hashCode() {
        return num;
    }

    @Override
    public boolean equals(Object obj) {
        return (obj instanceof HashBean)&&((HashBean) obj).num == num;
    }
}
public class Predtion {
    boolean shadow = Math.random() > 0.5;

    public String toString() {
        if(shadow)
            return "Six more weeks of Winter!";
        else       return "Early Spring!";
    }
}
public class ReHashTable {
    public static void main(String[] args) {
        Hashtable table = new Hashtable(  );
        for(int i = 0;i<10;i++){
//            int r = (int) (Math.random()*5);
            table.put( new HashBean(i),new Predtion());
        }

        HashBean h = new HashBean( 3 );
        if(table.containsKey( h )){
            System.out.println((Predtion)table.get( h ));
        }
    }
}
public class Person {
    String name ;
    int age ;

    public Person(){

    }
    public Person(String name,int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime*1 + result;
        result = prime*result + ((name == null)?0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        //提高效率
        if(this == obj) {
            return true;
        }
        if(obj == null) {
            return false;
        }
        //提高代码健壮性,不是同一个类型就直接返回false,省得向下转型了
        if(this.getClass() != obj.getClass()) {
            return false;
        }
        //向下转型
        Person p = (Person)obj;
        if(this.age != p.age) {
            return false;
        }
        if(this.name == null) {
            if(p.name != null) {
                return false;
            }

        }
        else if(!this.name.equals(p.name)) {
            return false;
        }
        return true;
    }

    public static void main(String[] args) {
        HashSet set = new HashSet(  );
        Person p1 = new Person( "jack" ,1  );
        Person p2 = new Person( "david",11 );
        Person p3 = new Person( "david",11 );
        //修改了hash方法,去重
        set.add( p1 );
        set.add( p2 );
        set.add( p3 );
    }
}

支持快速排序的容器

//比较函数接口,用于排序
public interface Compare {
    boolean lessThan(Object obj1 , Object obj2);

    boolean lessThanOrEqual(Object obj1 , Object obj2);
}

//继承vector的重写排序功能的容器
public class SortVector extends Vector {

    private Compare compare;

    public SortVector(Compare compare){
        this.compare = compare;
    }

    public void sort(){
        quicksort(0,size()-1);
    }

    //快速排序
    public void quicksort(int left,int right){
        if(left<right) {
            Object obj1 = elementAt( right );//last element
            int i = left - 1;
            int j = right;
            while (true) {
                while (compare.lessThan( elementAt( ++i ),obj1 )) ;
                //需要实现的比较函数。在创建容器时需要实现比较函数
                while (j > 0)
                    if (compare.lessThanOrEqual( elementAt( --j ),obj1 ))
                        break;
                if (i >= j)
                    break;
                swap( i,j );
            }

            swap( i,right );
            //确定了i的位置,继续递归
            quicksort( left,i - 1 );
            quicksort( i + 1,right );
        }
    }

    private void swap(int left,int right){
        Object tmp = elementAt(left);
        setElementAt(elementAt(right), left);
        setElementAt(tmp, right);
    }
}

//实现了String类型比较的比较方法
public class StringSortTest {

    //实现compare方法
    static class StringCompare implements Compare {
        public boolean lessThan(Object l,Object r) {
            return ((String) l).toLowerCase().compareTo( ((String) r).toLowerCase() ) < 0;
        }

        public boolean lessThanOrEqual(Object l, Object r) {
            return ((String)l).toLowerCase().compareTo( ((String)r).toLowerCase()) <= 0;     }
    }

    public static void main(String[] args) {
        SortVector sv = new SortVector( new StringCompare() );
        sv.addElement("d");
        sv.addElement("A");
        sv.addElement("C");
        sv.addElement("c");
        sv.addElement("b");
        sv.addElement("B");
        sv.addElement("D");
        sv.addElement("a");

        sv.sort();
        Enumeration e = sv.elements();
        while(e.hasMoreElements())
            System.out.println(e.nextElement());
    }
}

违例差错控制

throw 与throws的区别

程序捕获违例并抛出异常,常用的在方法名后 throws exception ,或使用try{  }catch(Exception e){  handle()},throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理,而.throw:,要么自己捕获异常(也就是try catch处理),要么声明抛出一个异常(就是throws 异常)。

public class ExceptionTest {
    public static void  division() {
        try{
            int num1 = 3;
            int num2 = 0;
            int ret =  num1/num2;
        }catch (ArithmeticException e){
            System.out.println("test");
        }
    }

    public static void main(String[] args) {

        division( );
    }
}
//输出
Ficom.weixy.think.sortPackage.ExceptionTest
Connected to the target VM, address: '127.0.0.1:3188', transport: 'socket'
test
Disconnected from the target VM, address: '127.0.0.1:3188', transport: 'socket'

而如果是方法后添加throws ArithmeticException ,
//输出
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at com.weixy.think.sortPackage.ExceptionTest.division(ExceptionTest.java:15)
	at com.weixy.think.sortPackage.ExceptionTest.main(ExceptionTest.java:21)
将异常抛出

创建自己的违例

//一个继承了Exception的自定义异常
public class MyException extends Exception {
    public MyException(){
    }

    public MyException(String msg){
        super(msg);
    }
}

public class Inheriting {
    public static void f() throws MyException {
        System.out.println(       "Throwing MyException from f()");
        throw new MyException();
    }

    public static void g() throws MyException {
        System.out.println(       "Throwing MyException from g()");
        throw new MyException("Originated in g()");
    }

    public static void main(String[] args) {
        try{
            f();
        }catch (MyException e){
            e.printStackTrace();
        }

        try {
            g();
        } catch (MyException e) {
            e.printStackTrace();
        }
    }
}

//抛出自定义异常的测试方法
Disconnected from the target VM, address: '127.0.0.1:3589', transport: 'socket'
com.weixy.think.sortPackage.MyException
Throwing MyException from f()
Throwing MyException from g()
	at com.weixy.think.sortPackage.Inheriting.f(Inheriting.java:13)
	at com.weixy.think.sortPackage.Inheriting.main(Inheriting.java:23)
com.weixy.think.sortPackage.MyException: Originated in g()
	at com.weixy.think.sortPackage.Inheriting.g(Inheriting.java:18)
	at com.weixy.think.sortPackage.Inheriting.main(Inheriting.java:29)

在处理异常之后,finally 用作担保内存的正确释放和保证工作的状态。

finally代码区

finally在异常处理时提供finally块来执行任何清除操作。无论有没有异常被抛出、捕捉,finally块都会被执行。

java的IO

java与字节流和字符流

字节流与字符流的区别

  字节流和字符流的区别在于所操作的数据单元不同,字节流操作的数据单元是8位的字节,字符流操作的数据单元是16位的字符。      字节流主要由 InputStream 和 OutputStream作为基类,字符流主要有 Reader 和 Writer作为基类
       int read(char[] b, int off, int len): 从输入流中最多读取 len 个字符的数据,并将其存入数组b中,从off位置开始读,返回实际读取的字符数。

public class FileInputStreamTest {

    //字符输入流
    public static void inStream() throws IOException {
        //创建字节输入流,相当于从管道中取数据,,绝对路径
        FileInputStream  inputStream = new FileInputStream( "file/file1/inFile.txt" );

        byte[] buf = new byte[1024];//缓存大小
        int hasRead = 0;
        //读取缓存中的数据。读取到缓存数组中去
        while ((hasRead = inputStream.read(buf)) > 0){
            //取出字节,将字节数组转换成字符串数输入
            System.out.println(new String(buf,0,hasRead));
        }
        inputStream.close();
    }

    //字符输出流
    public static void outStream() throws IOException {
        //创建输入流
        FileInputStream inputStream = new FileInputStream( "file/file1/inFile.txt"  );
        //创建输出流
        FileOutputStream outputStream = new FileOutputStream( "file/file1/outFile.txt");

        byte[] buf = new byte[1024];
        int hasRead = 0;
        while((hasRead = inputStream.read(buf)) > 0){
            outputStream.write( buf,0,hasRead );
            System.out.println("字符输出流向写入");
        }
        inputStream.close();
        outputStream.close();
    }

    //字节输入流
    public static void read() throws IOException {
        FileReader reader = new FileReader( "file/file1/inFile.txt" );
        char[] cbuf = new char[32];
        int hasRead = 0;
        while((hasRead = reader.read( cbuf )) > 0 ){
            System.out.println( new String( cbuf , 0 , hasRead ));
        }
        reader.close();

    }

    //字节输出流
    public static void write() throws IOException {
        //append 字段是是否添加,默认false,写入时覆盖写入
        FileWriter writer = new FileWriter( "file/file1/outFile.txt" ,true);
        writer.write( "锄禾日当午\r\n" );//\r\n 加入的地方会换行
        writer.write( "汗滴禾下土\r\n" );
        writer.flush();//
        writer.close();

    }



    public static void main(String[] args) throws IOException {

        //字符流和字节流输入
//        inStream();
//        read();

        //字符流和字节流输出
//            outStream();
            write();

    }

}

缓冲流(BufferedInputStream,BufferedOutputStream

BufferedInputStreamBufferedOutputStream这两个类分别是FilterInputStreamFilterOutputStream的子类

  • BufferedInputStream 是缓冲输入流。它继承于FilterInputStream

  • BufferedInputStream 的作用是为另一个输入流添加一些功能,例如,提供“缓冲功能”以及支持mark()标记reset()重置方法

  • BufferedInputStream 本质上是通过一个内部缓冲区数组实现的。例如,在新建某输入流对应的BufferedInputStream后,当我们通过read()读取输入流的数据时,BufferedInputStream会将该输入流的数据分批的填入到缓冲区中。每当缓冲区中的数据被读完之后,输入流会再次填充数据缓冲区;如此反复,直到我们读完输入流数据位置。

  • 使用缓冲流实现文档拷贝复制操作,关闭时的顺寻为先打开后关闭,因为缓存流是输入输出流的继承,在关闭缓存流时会关闭输入输出流,所以在最后的关闭时之关闭缓流就可以关闭输入输出流。

  • public static void main(String[] args) throws IOException {
    
            OutputStream outStream = null;
            InputStream inStream = null;
            BufferedInputStream bufferIn = null;
            BufferedOutputStream bufferOut = null;
            try {
                File file1 = new File( "file/file1/inFile.txt" );
                File file2 = new File( "file/file1/outFile.txt" );
    
                //输入,读数据
                inStream = new FileInputStream( file1 );
                bufferIn = new BufferedInputStream( inStream );
    
                //输出。写入数据
                outStream = new FileOutputStream( file2 );
                bufferOut = new BufferedOutputStream( outStream );
    
    //            InputStreamReader is = new InputStreamReader( inStream );
    //            BufferedReader br = new BufferedReader( is );
    //            br.readLine();//读取一行数据源
    
                byte[] buf = new byte[1024]; //一次的读入数据最大为1KB
                int hasRead = 0;
    
                while ((hasRead = bufferIn.read( buf )) > 0) {
                    bufferOut.write( buf,0,hasRead );//读取到二点数据写入到缓存中去
                }
                bufferOut.flush();//将缓存区的数据写入到文件中
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                bufferOut.close();
                bufferIn.close();         
            }
        }
    }

     

 

 

java 中的 lambda表达式写法

lambda是捕获参数进入到方法中去,类似快速进入方法中去

public class LambdaTest {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(  );
        list.add( "a" );
        list.add( "b" );
        list.add( "c" );
        list.add( "d" );
        
        for(String str : list){
            System.out.println(str);
        }
        //使用lamdba来捕获;ist中的每一个元素,再将它打印出来
        list.forEach( str  -> System.out.println(str));
    }
}

下面的代码是一些lambda的基础用法。

   public static void main(String[] args) {
        //匿名类继承Runnable,返回上述造型为runnable的句柄
        new Thread( new Runnable() {
            @Override
            public void run() {
                System.out.println("hello world runnable 1");
            }
        } ).start();
        //实现runnable  lamdba表达式
        Runnable run = () -> System.out.println("Hello world runnable 2");
        run.run();

        //使用lamdba 表达式进行排序
        String[] players = {"Rafael Nadal", "Novak Djokovic","Stanislas Wawrinka", "David Ferrer",
                            "Roger Federer", "Andy Murray","Tomas Berdych", "Juan Martin Del Potro",
                            "Richard Gasquet", "John Isner" };

        //利用lambda表达式进行数据的比较排序。
        Arrays.sort( players,(String s1,String s2) -> (s1.compareTo( s2 )) );

        //利用lambda重写比较方法
        Comparator<String> sortByName = (String s1,String s2) ->(s1.compareTo( s2 ));
        Arrays.sort( players,sortByName );

    }

java反射机制

反射就是把Java类中的各种成份影射成一个个的Java对象。例:一个类有:成员变量,方法,构造方法等,包等等信息,利用反射技术可以对一个类进行剖析,把各个组成部分影射成一个个对象

Class类—可获取类和类的成员信息
Field类—可访问类的属性
Method—可调用类的方法
Constructor—可调用类的构造方法

public class Student {
    String name;
    int age;
    double score;

    public Student() {
    }
    public Student(String name,int age,double score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public double getScore() {
        return score;
    }
    public void setScore(double score) {
        this.score = score;
    }
    public void learn(){
        System.out.println(name+" 学习中");
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }
 public static void main(String[] args) throws ClassNotFoundException {
        Student s = new Student();

        System.out.println("*********反射 Student 类型*********");

        Class stu1 = s.getClass();

        Class stu2 = Student.class;

        Class stu3 = Class.forName( "com.weixy.think.IOtest.Student" );

        System.out.println(stu1);

        System.out.println(stu2);

        System.out.println(stu3);

        System.out.println("*********反射 Student 属性*********");

        Field[] fields = stu1.getDeclaredFields();//获取对象的属性
        for(Field field : fields){
            String fieldName = field.getName();//获取属性名称
            Class type = field.getType();//获取属性类型
            int mod = field.getModifiers();//修饰类型对应的整数
            String modify = Modifier.toString( mod );//public,private,protected
            System.out.println( modify+ " " + type + "  " + fieldName  );
        }
        System.out.println("*********反射 Student 方法*********");
        Method[] methods = stu1.getMethods();
        for(Method method : methods){
            String methodName = method.getName();//获取方法名称
            Class returnType = method.getReturnType();//返回值类型
            String modStr=Modifier.toString(method.getModifiers());   
            // 获取方法的修饰符
            Class<?>[] paramTypes=method.getParameterTypes();   // 获取参数类型
          System.out.print(modStr+" "+returnType.getSimpleName()+" "+methodName+"(");

            if(paramTypes.length==0){
                System.out.print(")");
            }
            for(int i=0;i<paramTypes.length;i++){   // 遍历形式参数类型
                if(i==paramTypes.length-1){
                    System.out.print(paramTypes[i].getSimpleName()+" args"+i+")");
                }else{
                    System.out.print(paramTypes[i].getSimpleName()+" args"+i+",");
                }
            }
            System.out.println();
        }
    }
}

网络编程(Socket 套接字)

这是书上给出的一种比较简单的一个服务和一个客户的套接字传输数据的方法

public class JabberServer {
    public static final int PORT = 8080;
    public static void main(String[] args)        throws IOException {
        ServerSocket s = new ServerSocket(PORT);//服务端的监听地址和接口
        System.out.println("Started: " + s);
        try {       // Blocks until a connection occurs:
            Socket socket = s.accept();
            try {
                System.out.println("Connection accepted: "+ socket);
                BufferedReader in = new BufferedReader( new InputStreamReader( socket.getInputStream()));
                PrintWriter out =  new PrintWriter( new BufferedWriter( new OutputStreamWriter(  socket.getOutputStream())),true);
                while (true) {//接受Client的发送消息
                    String str = in.readLine();
                    if (str.equals("END")) break;
                    System.out.println("Echoing: " + str);
                    out.println(str);
                    }       // Always close the two sockets...
               } finally {
                System.out.println("closing...");
                socket.close();
            }
        } finally {
            s.close();
        }
    }
}


public class JabberClient {

    public static void main(String[] args) throws IOException {
        InetAddress addr =        InetAddress.getByName(null);//默认本地的地址
        System.out.println("addr = " + addr);
        Socket socket = new Socket(addr, JabberServer.PORT);
        try {
            System.out.println("socket = " + socket);
            BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream()));
            // Output is automatically flushed       // by PrintWriter:
            PrintWriter out =new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
            for(int i = 0; i < 10; i ++) {
                out.println("howdy " + i+"default");//向套接字钟写入数据,并刷新缓存区
                String str = in.readLine();//获取对面套接字的传送来的数据
                System.out.println(str+"receive");
            }       out.println("END");
        } finally {
            System.out.println("closing...");
            socket.close();
        }
    }
}

对于多线程的实现

public class JabberClientThread extends Thread {//实现多个线程创建的Thread继承类
    private Socket socket;
    private BufferedReader in;
    private PrintWriter out;
    private static int counter = 0;
    private int id = counter++;
    private static int threadcount ;

    public static int threadCount() {
        return threadcount;
    }

    public JabberClientThread(InetAddress addr) throws IOException {
        System.out.println( "Making client " + id );
        threadcount++;
        try {
            socket = new Socket( addr,MultiJabberServer.PORT );
        } catch (IOException e) {
            // If the creation of the socket fails,
            // nothing needs to be cleaned up.
        }
        try {
            in = new BufferedReader( new InputStreamReader( socket.getInputStream() ) );
            out = new PrintWriter( new BufferedWriter( new OutputStreamWriter( socket.getOutputStream() ) ),true );
            start();
        } catch (IOException e) {
            // The socket should be closed on any
            // failures other than the socket
            // constructor:
            try {
                socket.close();
            } catch (IOException e2) {
            }
        }
    }

    /**
     * 发送数据到套截至中,结尾添加终止字符"END"
     */
    public void run(){
        try {
            for(int i = 0; i < 25; i++) {
                out.println("Client " + id + ": " + i);
                String str = in.readLine();
                System.out.println(str);
            }
            out.println("END");
        } catch(IOException e) {     }
        finally {         try {         socket.close();
        } catch(IOException e) {}
        threadcount--;
        }
    }
}

public class MultiJabberClient {
    static final int MAX_THREADS = 40;
    public static void main(String[] args) throws IOException, InterruptedException {
        InetAddress addr = InetAddress.getByName(null);

        while(true) {
            if(JabberClientThread.threadCount() < MAX_THREADS) { 
        //创建最多40个线程同时向服务端发送数据
                new JabberClientThread( addr );
                System.out.println( "count:  " + JabberClientThread.threadCount() );
            }

            Thread.currentThread().sleep(100);
        }
    }
}

服务端,每次接受一个连接的时候,常数获取对应的套接字

public class ServeOneJabber extends Thread {
    private Socket socket;
    private BufferedReader in;
    private PrintWriter out;

    public ServeOneJabber(Socket s) throws IOException {
        socket = s;
        in = new BufferedReader( new InputStreamReader( socket.getInputStream() ) );
        out = new PrintWriter( new BufferedWriter( new OutputStreamWriter( socket.getOutputStream() ) ),true );
        start();//开启run方法
    }

    /**
     * 读取套接字的类容平打印和返回给套接字
     */
    public void run() {
        try {
            while (true) {
                String str = in.readLine();
                if (str.equals("END"))
                    break;
                System.out.println("Echoing: " + str);
                out.println(str);
            }
                System.out.println("closing...");
        } catch (IOException e) {     }
        finally {
            try { socket.close();
            } catch(IOException e) {}
        }
    }
}
public class MultiJabberServer {
    static final int PORT = 8080;

    public static void main(String[] args)       throws IOException {
        ServerSocket s = new ServerSocket(PORT);
        System.out.println("Server Started");
        try {
            while(true) {
                //阻塞,直到一个连接建立起来
                Socket socket = s.accept();
                try {
                    new ServeOneJabber(socket);  //创建一个服务该端口的套接字
                } catch(IOException e) {
                    // If it fails, close the socket,
                    // otherwise the thread will close it:
                    socket.close();
                }
            }
        } finally {
            s.close();
        }
    }
}

socket的传输控制协议为TCP的,是一有状态的连接方式。其中TCP连接建立起来需要四次握手 ,断开时需要三次回收,这个地方我准备新开一篇文章,学习HTTP/TCP协议,通常一个服务器可能需要接受多个客户端的请求,如果是一对一的处理是很慢而且浪费时间。利用线程池可以提升服务端的性能

public class SocketMultiService {

    public static void main(String[] args) throws IOException {
        int PORT = 7777;//端口号

        ExecutorService threadPool = Executors.newFixedThreadPool( 50 );//线程池多线程处理多个客户端请求
        ServerSocket serverSocket = new ServerSocket( PORT );//创建监听特定端口监听器
        System.out.println( "server wait connection" );

        try {
            serverSocket.setSoTimeout( 3000 );//3S无连接请求超时,服务端关闭
            while (true) {
                Socket s = serverSocket.accept();//当监听器监听到有连接请求创建套接字
                //创建一个匿名类来实现处理消息的接受与返回
                Runnable runnable = new Runnable() {
                    @Override
                    public void run() {
                        try {
                            //读取输入信息
                            InputStream in = s.getInputStream();
                            //自动刷新缓存
                            PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter( s.getOutputStream() ) ),true );
                            byte[] buf = new byte[1024];//缓存
                            int len = 0;
                            StringBuilder sb = new StringBuilder();
                            while ((len = in.read( buf )) > 0) {//读取输入流的数据放入到数组中
                                sb.append( new java.lang.String( buf,0,len - 1 ) );
                            }
                            System.out.println( sb );
                            out.write( "back to client " + sb );//返回给客户端

                            System.out.println( "get message from client: " + sb );
                            in.close();
                            s.close();

                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                };
                threadPool.submit( runnable );
            }
        } catch (SocketTimeoutException e) {
            System.out.println("服务端关闭");
        } finally {
            serverSocket.close();
            threadPool.shutdownNow();
//shutDown和shutDownNow的区别是,shutDown会将线程池置为shutDown,在已经添加到线程池的任务完成之后才会退出。
//而shutDownNow将线程池置为Stop的状态,并试图停止所有正在执行的线程,不再处理还在池队列中等待的任务,返回那些未执行的任务。 
        }
    }
}

客户端用线程池模拟多个请求同时发送,

public class SocketMultiClient {


    public static void main(String[] args) throws IOException {

        ExecutorService threadPool = Executors.newFixedThreadPool( 50 );

        for( int i=0;i<30;i++){
            int oreder = i;
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    //建立与服务端通信的套接字
                    Socket socket = null;
                    try {
                        socket = new Socket( InetAddress.getLocalHost(),7777 );
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    //获取连接的输入流和输出流。
                    OutputStream out = null;
                    try {
                        out = socket.getOutputStream();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    try {
                        InputStream in = socket.getInputStream();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    System.out.println("order = " + oreder);
                    String msg = "id: "+oreder+"  client send message ";
                    byte[] by = msg.getBytes();
                    try {
                        out.write( by );
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            };
            threadPool.submit( runnable );
        }
        System.out.println("客户端关闭");
        threadPool.shutdownNow();
    }
}

网络编程还需要努力学习,ThinkingInJava虽然知识面特别广,但是很多的实现细节需要解释的不是很清楚,需要自己去研读源码,2019、努力奋斗

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值