Java面向对象中类与对象的概念和使用
构造方法的主要作用 一是用来实例化该类。二是 让该类实例化的时候执行哪些方法,初始化哪些属性。当一个类声明了构造函数以后,JVM 是不会再给该类分配默认的构造函数。
构造方法是一种特殊的方法,具有以下特点。
(1)构造方法的方法名必须与类名相同。
(2)构造方法没有返回类型,也不能定义为void,在方法名前面不声明方法类型。
(3)构造方法的主要作用是完成对象的初始化工作,它能够把定义对象时的参数传给对象的域。
(4)构造方法不能由编程人员调用,而要系统调用。
(5)一个类可以定义多个构造方法,如果在定义类时没有定义构造方法,则编译系统会自动插入一个无参数的默认构造器,这个构造器不执行任何代码。
(6)构造方法可以重载,以参数的个数,类型,或排列顺序区分
重载与重写:
重载是在同一个类中的两个或两个以上的方法,拥有相同的方法名,但是参数却不相同,方法体也不相同,最常见的重载的例子就是类的构造函数
重写是子类的方法覆盖父类的方法,发生在继承中,要求方法名,参数类型和返回值都相同。被重写的方法不能拥有比父类更严格的权限(public>protected>default>private)
// Person.java
package com.example;
public class Person{
String name;
int age;
public Person(String name,int age){ //构造方法
this.name=name;
this.age=age;
}
public Person(String name){ //方法重载,对参数类型或个数,权限均无要求
this.name=name;
System.out.println(name);
}
public void tell(){
System.out.println(name +":" + age);
}
}
// Main.java
import com.example.Person;
public class Main {
public static void main(String[] args) {
Person p =new Person("zhang",17);
p.tell();
Person q =new Person("Li"); // 实例化的时候调用重载构造方法
}
}
Java面向对象的基本特征之封装性
封装就是隐藏实现细节,将属性私有化,提供公有方法访问私有属性。
// Person.java
package com.example;
public class Person{
private String name;
private int age; //将类的成员变量声明为private
public void setName(String name) { //通过public的方法对变量进行访问
this.name = name; //一般定义两个方法实现这两种操作,即:setxx()与getxx()
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void tell(){
System.out.println(getName() +":" + getAge());
}
}
// Main.java
import com.example.Person;
public class Main {
public static void main(String[] args) {
Person p =new Person();
p.setName("Zhang");
p.setAge(17);
p.tell();
}
}
Java面向对象基本特征之继承
JAVA只支持单继承,一个类只能有一个父类,同时一个类可以实现多个接口,从而克服单继承的缺点。
子类不能直接访问父类private成员,可用set,get方法;
子对象的实例化过程先调用父类的构造方法,在调用子类的构造方法;
子类重写父类方法之后(方法名称,返回类型,参数都相同),不能拥有比父类更严格的访问权限(public>protected>default>private)
Super关键字强行执行父类方法
继承: class 子类 extends 父类{}
// Person.java
package com.example;
class Person{
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Person(int n){ //有参数的构造方法
System.out.println("Person() constructor is called !");
}
}
// Student.java
package com.example;
public class Student extends Person{ //继承
private int score;
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public void tell() {
System.out.println(getName() +": 得分"+getScore());
}
public Student() { //构造方法的继承
super(200);//构造方法先引用父类的构造方法,编译器找不到无参方法就报错.必须在子类构造方法最上面加一句super(int值)才可以通过编译.
System.out.println("Student() constructor is called !");
}
}
// Main.java
import com.example.Student;
public class Main {
public static void main(String[] args) {
Student s= new Student();
s.setName("Zhang");
s.setScore(100);
s.tell();
}
}
Java面向对象基本特征之多态
什么是多态
面向对象的三大特性:封装、继承、多态。从一定角度来看,封装和继承几乎都是为多态而准备的。这是我们最后一个概念,也是最重要的知识点。
多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。
多态的作用:消除类型之间的耦合关系。
现实中,关于多态的例子不胜枚举。比方说按下 F1 键这个动作,如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;如果当前在 Word 下弹出的就是 Word 帮助;在 Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果。
下面是多态存在的三个必要条件,要求大家做梦时都能背出来!
多态存在的三个必要条件!
一、要有继承;
二、要有重写;
三、父类引用指向子类对象。
多态的好处:
1.可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。
2.可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。
3.接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。如超类Shape规定了两个实现多态的接口方法,computeArea()以及computeVolume()。子类,如Circle和Sphere为了实现多态,完善或者覆盖这两个接口方法。
4.灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。
5.简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。
Java中多态的实现方式:接口实现,继承父类进行方法重写,同一个类中进行方法重载。
//父类
class Father {
//父类有一个打孩子方法
public void hitChild(){}
}
//子类1
class Son1 extends Father {
//重写父类打孩子方法
public void hitChild() {
System.out.println("为什么打我?我做错什么了!");
}
}
//子类2
class Son2 extends Father{
//重写父类打孩子方法
public void hitChild(){
System.out.println("我知道错了,别打了!");
}
}
//子类3
class Son3 extends Father{
//重写父类打孩子方法
public void hitChild(){
System.out.println("我跑,你打不着!");
}
}
//测试类
public class Main {
public static void main(String args[]){
Father father;
father = new Son1();
father.hitChild();
father = new Son2();
father.hitChild();
father = new Son3();
father.hitChild();
}
}
Java面向对象-抽象类与接口
抽象类的特点:
1:包含一个抽象方法的类,抽象类和抽象方法必须由abstract关键字修饰(可以描述类和方法,不可以描述变量)。
2:抽象方法只定义方法声明,并不定义方法实现。
3:抽象类不可以被创建对象(实例化)。
4:只有通过子类继承抽象类并覆盖了抽象类中的所有抽象方法后,该子类才可以实例化。否则,该子类还是一个抽象类。子类必须重写抽象类中的所有抽象方法!
抽象类定义格式: abstract class className{属性;方法;抽象方法}
abstract class Person{
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public abstract void tell();
public abstract void say();
}
class Student extends Person{
public void tell(){
System.out.println(getName());
}
public void say(){}; //子类必须重写抽象类中的所有抽象方法!
}
public class Main {
public static void main(String[] args) {
Student s= new Student();
s.setName("Zhang");
s.tell();
}
}
接 口:
1:是用关键字interface定义的特殊的类。里面全部由全局常量和公共的抽象方法组成。
interface Inter{
全局常量:public static final
抽象方法:public abstract
}
2:接口中有抽象方法,说明接口不可以实例化。接口的子类必须实现了接口中所有的抽象方法后,该子类才可以实例化。否则,该子类还是一个抽象类。子类必须重写抽象类中的所有抽象方法!
3:类与类之间存在着继承关系,类与接口中间存在的是实现关系。
继承用extends ;实现用implements ;
4:接口和类不一样的地方,就是,接口可以被多实现,这就是多继承改良后的结果。java将多继承机制通过多实来体现。
5:一个类在继承另一个类的同时,还可以实现多个接口。所以接口的出现避免了单继承的局限性。还可以将类进行功能的扩展。
interface Inter1{
public static final int num1 = 1;
public abstract void tell();
}
interface Inter2{
public static final int num2 = 2;
public abstract void say();
}
//一个接口通过extends关键字同时继承多个接口
interface Inter3 extends Inter1,Inter2{
public static final int num3 = 3;
public abstract void call();
}
abstract class Abs{
public abstract void print();
}
//通过子类实现接口
class A implements Inter1,Inter2 {
public void tell(){
System.out.println("A实现了接口" + num1);
}
public void say(){
System.out.println("A实现了接口" + num2);
}
}
//通过子类继承抽象类同时实现接口
class B extends Abs implements Inter3 {
public void tell(){};
public void say(){};
public void call(){
System.out.println("B实现了接口3,且继承了接口" + num1 + "," + num2);
}
public void print(){
System.out.println("B继承抽象类Abs");
}
}
public class Main {
public static void main(String[] args) {
A a=new A();
a.tell();
a.say();
B b=new B();
b.print();
b.call();
}
}
Java面向对象-泛型
泛型是Java SE1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安全简单。
泛型类:
public class Main<T> { //在类名后面添加了类型参数声明部分
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
public static void main(String[] args) {
Main<Integer> integerBox = new Main<Integer>();//对象创建:在类名后面添加具体类型
Main<String> stringBox = new Main<String>();
integerBox.set(new Integer(10));
stringBox.set(new String("Hello World"));
System.out.printf("Integer Value:%d\n", integerBox.get());
System.out.printf("String Value:%s\n", stringBox.get());
}
}
泛型方法将数组排序输出:
import java.util.Arrays;
public class Main {
// 泛型方法 printArray
public static <E> void printArray(E[] inputArray)
{
//排序
Arrays.sort(inputArray);
// 输出数组元素
for (E element : inputArray) {
System.out.printf("%s ", element);
}
System.out.println(); //换行
}
public static void main( String args[] ) {
// 创建不同类型数组: Integer, Double 和 Character
Integer[] intArray = { 1, 5, 3, 2, 5 };
Double[] doubleArray = { 3.3, 2.2, 1.1, 4.4 };
Character[] charArray = { 'C', 'A', 'E', 'B', 'D' };
System.out.println( "Array integerArray contains:" );
printArray(intArray); // 传递一个整型数组
System.out.println( "Array doubleArray contains:" );
printArray(doubleArray); // 传递一个双精度型数组
System.out.println( "Array characterArray contains:" );
printArray(charArray); // 传递一个字符型型数组
}
}
Java集合类详解
Collection集合类的基本结构:
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
Map (key----> value)
├Hashtable
├HashMap
└WeakHashMap
1、Collection接口
Collection是最基本集合接口,它定义了一组允许重复的对象。Collection接口派生了两个子接口Set和List,分别定义了两种不同的存储方式。
2、 Set接口
Set接口继承于Collection接口,它没有提供额外的方法, Set接口的集合类中的元素是不可重复的。但是可以排序。
两个常用子类:
1.散列存放:HashSet;
2.有序存放:TreeSet;
3、 List接口
List接口同样也继承于Collection接口,但是与Set接口恰恰相反,List接口的集合类中的元素是对象有序且可重复。
特征:有序且可重复。
两个重要的实现类:ArrayList和LinkedList
1.ArrayList特点是有序可重复的
2.LinkedList是一个双向链表结构的。
4、Map接口
Map也是接口,但没有继承Collection接口。该接口描述了从不重复的键到值的映射。Map接口用于维护键/值对(key/value pairs)。
特征:它描述了从不重复的键到值的映射。
两个重要的实现类:HashMap和TreeMap
1.HashMap,中文叫散列表,基于哈希表实现,特点就是键值对的映射关系。一个key对应一个Value。HashMap中元素无序存放,Key不允许重复。更加适合于对元素进行插入、删除和定位。
2.TreeMap,基于红黑书实现。TreeMap中的元素保持着某种固定的顺序。更加适合于对元素的顺序遍历。
5、Iterator接口
Iterator接口,在C#里有例外一种说法IEnumerator,他们都是集合访问器,用于循环访问集合中的对象。所有实现了Collection接口的容器类都有iterator方法,用于返回一个实现了Iterator接口的对象。Iterator对象称作迭代器,Iterator接口方法能以迭代方式逐个访问集合中各个元素,并可以从Collection中除去适当的元素。
6、Comparable接口
Comparable可以用于比较的实现,实现了Comparable接口的类可以通过实现comparaTo方法从而确定该类对象的排序方式。
List接口,Iterator接口:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
//添加元素
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
list.add(null);
//遍历
for (String string : list) {
System.out.println(string);
}
System.out.println("-------修改list--------");
//修改
list.set(1, "bbb2");
//删除
list.remove("ccc");
//迭代器遍历
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("--------添加list-------");
List<String> list2 = new ArrayList<String>();
list2.add("a");
list2.add("b");
//将list2添加到list中
list.addAll(list2);
//遍历
for (String string : list) {
System.out.println(string);
}
System.out.println("清空前list的大小"+list.size());//打印大小
list.clear(); //清空列表
System.out.println("清空后list的大小"+list.size());//打印大小
}
}
HashMap接口,set,collection,Iterator接口:
import java.util.*;
public class Main {
public static void main(String[] args) {
Map<String,String> map = new HashMap<String,String>();
map.put("1","A");
map.put("2.5","B");
map.put("123L","C");
String str = map.get("1");
System.out.println(str);
System.out.println(map.size());
System.out.println(map.containsKey("2.5"));
System.out.println(map.containsValue("D"));
//输出所有key
Set<String> s = map.keySet();
Iterator<String> i = s.iterator();
while(i.hasNext()){
System.out.println(i.next());
}
//输出所有value
Collection<String> c = map.values();
Iterator<String> j = c.iterator();
while(j.hasNext()){
System.out.println(j.next());
}
}}
Java本地文件操作
File类操作:
import java.io.*;
public class Main {
public static void main(String[] args) {
File folder = new File("E:\\new");
folder.mkdirs(); //创建文件夹
System.out.println("文件夹创建成功");
File folder1 = new File("E:\\test");
folder.renameTo(folder1); //重命名
System.out.println("重命名成功");
folder.delete();
File file = new File("E:\\test\\d.txt"); //查找文件
if(file.exists()){
System.out.println(file.isFile());
System.out.println(file.isDirectory());
}else{
System.out.println("文件不存在,马上进行创建!");
}
try {
file.createNewFile(); //创建文件
} catch (IOException e) {
e.printStackTrace();
}}}
Java中的IO操作
一:字节流
OutputStream和InputStream(基类)
FileOutputStream和FileInputStream(字节带缓冲输入、输出流)
BufferedInputStream和BufferedOutputStream(字节缓冲输入、输出流)
二:字符流
Reader和Writer(基类)
FileReader和FileWriter(定义字符输入、输出流)
BufferedReader和BufferedWriter(字符带缓冲输入、输出流)
LineNumberReader
IO操作:使用字节流读写数据
import java.io.*;
public class Main {
public static void main(String[] args) {
try {
File file1 = new File("E:\\test\\input.txt" );
file1.createNewFile();
//输出流:向文件中写数据
FileOutputStream fos=new FileOutputStream("E:\\test\\input.txt");
String outString="HelloWorld";
byte output[]=outString.getBytes("UTF-8");
fos.write(output);
//输入流:从文件中读取数据
FileInputStream fis = new FileInputStream("E:\\test\\input.txt");
byte input[]=new byte[20];
fis.read(input);
String s=new String(input,"UTF-8");
System.out.println(s);
//输出流:向另一文件中复制数据
File file2 = new File("E:\\test\\output.txt" );
file2.createNewFile();
FileOutputStream fos1=new FileOutputStream("E:\\test\\output.txt");
fos1.write(s.getBytes());
fis.close();
fos.close();
fos1.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}}}
带有缓冲的字符流读写数据:
import java.io.*;
public class Main {
public static void main(String[] args) {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//BufferedReader对象创建后获取控制台输入流
File file = new File("E:\\test\\output.txt");
try {
FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw);
//加了一个缓冲,缓冲写满后再将数据写入硬盘 ,极大的提高了性能
char[] cs = new char[50];
br.read(cs); //以使用read()方法从控制台读取一个字符
String s = new String(cs);
System.out.println(s.trim());
bw.write(s); //将字符串写入磁盘文件中
br.close();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Java多线程编程
一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守候线程都结束运行后才能结束。
Java提供了两种创建线程方法:
• 通过继承Thread类本身: class NewThread extends Thread{}
new NewThread().start();
• 通过实现Runable接口: class NewThread implements Runnable{}
new Thread( new NewThread()).start();
继承Thread类和实现Runnable接口实现多线程,一个是多个线程分别完成自己的任务,一个是多个线程共同完成一个任务。如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制(继承了Thread类就不能再继承其他类了)
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。
通过继承Thread类本身创建线程:
class NewThread extends Thread { //创建Thread的子类以控制线程的运行
public NewThread(String name){
super(name); //调用父类构造方法给thread命名
}
public void run() {
try {
for(int i = 5; i > 0; i--) {
System.out.println("Thread " + getName() + ":"+ i);
Thread.sleep(50); // 暂停线程,休眠
}
} catch (InterruptedException e) {
System.out.println("Child interrupted.");
}
System.out.println("Exiting child thread.");
}
}
public class Main {
public static void main(String args[]) {
NewThread t1=new NewThread("A");
NewThread t2=new NewThread("B");
NewThread t3=new NewThread("C");
t1.start();
t2.start();
t3.start();
System.out.println(t3.isAlive());//判断线程是否启动
}
}
通过实现Runnable接口创建线程:
class NewThread implements Runnable {
String name;
public NewThread(String name){
this.name=name;
}
public void run() {
try {
for(int i = 5; i > 0; i--) {
System.out.println("Thread " + name + ":" + i);
Thread.sleep(50); // 暂停线程
}
} catch (InterruptedException e) {
System.out.println("Child interrupted.");
}
System.out.println("Exiting child thread.");
}
}
public class Main {
public static void main(String args[]) {
NewThread t1 = new NewThread("A");
Thread demo = new Thread(t1);
demo.start();
for(int i = 0; i < 5; i++) {
if(i > 1) {
try {
demo.join(); //等待线程结束
} catch(Exception e) {
e.printStackTrace();
}
}
System.out.println("main 线程执行-->"+i);
}
}
}
线程同步:
多线程环境中,可能存在多个线程同时使用某一资源造成资源冲突的情况(继承Thread类时)。多线程的同步依靠的是对象锁机制,synchronized关键字的背后就是利用了封锁来实现对共享资源的互斥访问。
例1:
class MyThread extends Thread { //创建Thread的子类以控制线程的运行
public MyThread(String name){
super(name);
}
public void run() {
while(true) {
sale();
}}
private static int tickets = 30;
public static synchronized void sale() { //这里就是对函数进行同步。
if(tickets > 0) {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 剩余票数:"+ tickets);
}
tickets--;
}
}
public class Main {
public static void main(String[] args) {
MyThread t1 = new MyThread("窗口A");
MyThread t2 = new MyThread("窗口B");
MyThread t3 = new MyThread("窗口C");
t1.start();
t2.start();
t3.start();
}
}
例2:
public class Main implements Runnable{
private int tickets = 10;
public void run() {
int count = 0;
while(true) {
synchronized(this) {
if(tickets > -1) {
try {
Thread.sleep(100);
} catch(InterruptedException e) {
e.printStackTrace();
}
count = 10 - tickets;
System.out.println("当前有:" + tickets + " 张票"
+ " ,售出:" + count + "张票"
+ " ,售票员为:" + Thread.currentThread().getName());
tickets--;
}else {
break;
}
}
}
}
public static void main(String[] args) {
Main r = new Main();
//调用Thread(Runnable threadOb,String threadName)构造方法.threadOb是一个实现Runnable 接口的类的实例,并且 threadName指定新线程的名字
Thread t1 = new Thread(r,"张三");
Thread t2 = new Thread(r,"李四");
Thread t3 = new Thread(r,"王五");
Thread t4 = new Thread(r,"赵六");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
Java中的Socket通信
Java socket通信已经被封装好了主要使用两个类ServerSocket 和Socket
首先写一个1v1的通信
Server:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class GreetingServer
{
// 设置端口号
public static int portNo = 3333;
public static void main(String[] args) throws IOException
{
ServerSocket s = new ServerSocket(portNo);
System.out.println("The Server is start: " + s);
// 阻塞,直到有客户端连接
Socket socket = s.accept();
try
{
System.out.println("Accept the Client: " + socket);
//设置IO句柄
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
while (true)
{
String str = in.readLine();
if (str.equals("byebye"))
{
break;
}
System.out.println("客户端发送的消息是: " + str);
out.println("服务器收到:"+str);
}
}
finally
{
System.out.println("close the Server socket and the io.");
socket.close();
s.close();
}
}
}
Client:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
public class GreetingClient
{
static String clientName = "Mike";
//端口号
public static int portNo = 3333;
public static void main(String[] args) throws IOException
{
// 设置连接地址类,连接本地
InetAddress addr = InetAddress.getByName("localhost");
//要对应服务器端的3333端口号
Socket socket = new Socket(addr, portNo);
try
{
System.out.println("socket = " + socket);
// 设置IO句柄
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(new BufferedWriter(
New OutputStreamWriter(socket.getOutputStream())), true);
out.println("Hello Server,I am " + clientName);
String str = in.readLine();
System.out.println(str);
out.println("byebye");
}
finally
{
System.out.println("close the Client socket and the io.");
socket.close();
}
}
}
通过程序里引入多线程的机制,可让一个服务器端同时监听并接收多个客户端的请求,并同步地为它们提供通讯服务。
基于多线程的通讯方式,将大大地提高服务器端的利用效率,并能使服务器端能具备完善的服务功能。
Server:
package tcp;
import java.io.*;
import java.net.*;
//第二步,由于我们在服务器端引入线程机制,所以我们要编写线程代码的主体执行类ServerThreadCode,这个类的代码如下所示:
class ServerThreadCode extends Thread
{
//客户端的socket
private Socket clientSocket;
//IO句柄
private BufferedReader sin;
private PrintWriter sout;
//默认的构造函数
public ServerThreadCode()
{}
public ServerThreadCode(Socket s) throws IOException
{
clientSocket = s;
//初始化sin和sout的句柄
sin = new BufferedReader(new InputStreamReader(clientSocket
.getInputStream()));
sout = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
clientSocket.getOutputStream())), true);
//开启线程
start();
}
//线程执行的主体函数
public void run()
{
try
{
//用循环来监听通讯内容
for(;;)
{
String str = sin.readLine();
//如果接收到的是byebye,退出本次通讯
if (str.equals("byebye"))
{
break;
}
System.out.println("In Server reveived the info: " + str);
sout.println(str);
}
System.out.println("closing the server socket!");
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
System.out.println("close the Server socket and the io.");
try
{
clientSocket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
public class ThreadServer
{
//端口号
static final int portNo = 3333;
public static void main(String[] args) throws IOException
{
//服务器端的socket
ServerSocket s = new ServerSocket(portNo);
System.out.println("The Server is start: " + s);
try
{
for(;;)
{
//阻塞,直到有客户端连接
Socket socket = s.accept();
//通过构造函数,启动线程
new ServerThreadCode(socket);
}
}
finally
{
s.close();
}
}
}
Client:
package tcp;
import java.net.*;
import java.io.*;
//第二步,编写线程执行主体的ClientThreadCode类,同样,这个类通过继承Thread来实现线程的功能。
class ClientThreadCode extends Thread
{
//客户端的socket
private Socket socket;
//线程统计数,用来给线程编号
private static int cnt = 0;
private int clientId = cnt++;
private BufferedReader in;
private PrintWriter out;
//构造函数
public ClientThreadCode(InetAddress addr)
{
try
{
socket = new Socket(addr, 3333);
}
catch(IOException e)
{
e.printStackTrace();
}
//实例化IO对象
try
{
in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(
new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
//开启线程
start();
}
catch(IOException e)
{
//出现异常,关闭socket
try
{
socket.close();
}
catch(IOException e2)
{
e2.printStackTrace();
}
}
}
//线程主体方法
public void run()
{
try
{
out.println("Hello Server,My id is " + clientId );
String str = in.readLine();
System.out.println(str);
out.println("byebye");
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
try
{
socket.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
}
//第三步,编写客户端的主体代码,在这段代码里,将通过for循环,根据指定的待创建的线程数量,通过ClientThreadCode的构造函数,创建若干个客户端线程,同步地和服务器端通讯。
public class ThreadClient
{
public static void main(String[] args)
throws IOException, InterruptedException
{
int threadNo = 0;
InetAddress addr =
InetAddress.getByName("localhost");
for(threadNo = 0;threadNo<3;threadNo++)
{
new ClientThreadCode(addr);
}
}
}
Java中的反射
反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
一个简单的例子:
public class Apple {
private int price;
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public static void main(String[] args) throws Exception{
//正常的调用
Apple apple = new Apple();
apple.setPrice(5);
System.out.println("Apple Price:" + apple.getPrice());
//使用反射调用
Class clz = Class.forName("com.chenshuyi.api.Apple"); // 获取类的 Class 对象实例, 也可以使用类对象的 getClass() 方法:apple.getClass();
Method setPriceMethod = clz.getMethod("setPrice", int.class);
Constructor appleConstructor = clz.getConstructor(); // 根据 Class 对象实例获取 Constructor 对象
Object appleObj = appleConstructor.newInstance(); // 使用 Constructor 对象的 newInstance 方法获取反射类对象, 也可以通过 Class 对象的 newInstance() 方法:clz.newInstance();
setPriceMethod.invoke(appleObj, 14); // 利用 invoke 方法调用方法
Method getPriceMethod = clz.getMethod("getPrice");
System.out.println("Apple Price:" + getPriceMethod.invoke(appleObj));
}
}