Java基础总结
1.基本类型
1.在程序设计中经常用到一系列类型(基本类型),它们需要特殊对待。对于这些类型,Java采取与C和C++相同的方法,也就是说,不用new来创建变量,出是创建一个并非引用的变量,这个变量直接存储“值”,并置于堆栈中,因此更加高效。
基本类型 | 包装类型 | 大小 |
---|---|---|
boolean | Boolean | - |
char | Character | 16-bit |
byte | Byte | 8-bit |
short | Short | 16-bit |
int | Integer | 32-bit |
long | Long | 64-bit |
float | Float | 32-bit |
double | Double | 64-bit |
void | Void | - |
基本类型具有的装类,使得可以在堆中创建一个非基本对象,用来表示对应的基本类型。
public class AutoBoxingTest{
public static final Integer CONST_A = 1;
public static final Integer CONST_B = Integer.valueOf("2");
public static final Integer CONST_C = new Integer(3);
private Integer status;
public void setStatus(Integer status){
this.status = status;
}
public void displayStatus(){
if(status==CONST_A)
System.out.println("It's CONST_A");
else if(status==CONST_B)
System.out.println("It's CONST_B");
else if(status==CONST_C)
System.out.println("It's CONST_C");
else
System.out.println("Invalid status!");
}
public static void main(String[] args){
AutoBoxingTest abt = new AutoBoxingTest();
abt.setStatus(1);
abt.displayStatus();
abt.setStatus(2);
abt.displayStatus();
abt.setStatus(3);
abt.displayStatus();
}
}
/**
执行结果:
It's CONST_A
It's CONST_B
Invalid status!
原因:
在自动装箱和调用Integer.valueOf(String)时,返回的Integer是从IntegerCache中获取的,所以都是同一个对象。
延伸一下,如果一边是包装类,一边是基本类型时,使用< 、> 、<=等比较,都会时行值比较。
*/
Java提供了两个用于高精度计算的类:BigInteger、BigDecimal。
import java.math.BigInteger;
public class MainClass{
public static void main(String[] argv)throws Exception
{
BigInteger bigInteger1 = new BigInteger("123456789012345678901234567890");
BigInteger bigInteger2 = new BigInteger("123456789012345678901234567890");
//add
bigInteger1 = bigIntger1.add(bigInteger2);
System.out.println(bigInteger1);
//subtract
bigInteger1 = bigInteger1.subtract(bigInteger2);
System.out.println(bigInteger1);
//multiplay
bigInteger1 = bigInteger1.multiply(bigInteger2);
System.out.println(bigInteger1);
//divide
bigInteger1 = bigInteger1.divide(bigInteger2);
System.out.println(bigIntger1);
}
}
2.基本数据类型默认值
若类的某个成员是基本类型,即使没有进行初始化,Java也会确保它获得一个默认值 。
基本类型 | 默认值 |
---|---|
boolean | false |
char | ‘/u0000’ |
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
float | 0.0L |
doubl | 0.0d |
3.javadoc
用于提取注释的一部分,输出是一个HTML文件,所有Javadoc命令只能在”/*”注释中出现,结束于”/”,使用Javadoc的方式主要有两种:嵌入式HTML或使用”文档标签”,”文档标签”是一些以@字符开头的命令.
数组
Java声明数组时不能指定其长度。
int a[5]//非法
//一维数组声明方式
type var[]或type[] var;
//动态 初始化
MyType data[] = new MyType[3];
data[0] = new MyType(1,2);
data[1] = new MyType(3,4);
//静态初始化
MyType data[]={
new MyType(1,2),
new MyType(3,4)
};
2.操作符
1.直接常量
为了编译器可以准确的知道要生成什么样的类型,可以给直接常量后面添加后缀字符标志它的类型,若为L表示long,F表示float,D表示double。也可以利用前缀表示进制,0x表示十六进制,0表示八进制。
2.移位操作符
(<<):向左移动,低位补0
(>>):向右移动,高位补符号
(>>>):向右移动,高位补0
3.Java中没有sizeof,因为所有数据类型在所有机器中的大小都是相同的。
3.控制执行流程
1.foreach
是一种更加简洁的for语法用于数组和容器
for(元素类型t 元素变量x:遍历对象obj){
引用x的java语句
}
int arr[] = {1,2,3};
for(int x:arr){
System.out.println(x);
}
4.初始化与清理
1.Java完全采用动态内存分配方式。每当想创建新对象时,就需要使用new关键字来构建此对象实例。
2.在构造器中,如果为this添加了参数列表,那么就有了不同的含义。这将产生对符合此参数列表的某个构造器的明确调用。(1)尽管可以用this调用一个构造器,但却不能调用两个,而且必须将构造器调用置于最起始处。(2)除构造器外,编译器禁止在其他任何方法中调用构造器。
public class Person{
int age = 0;
String name = "";
Person(int a){
age = a;
System.out.println("age:"+age);
}
Person(String n){
name = n;
System.out.println("name:"+name);
}
Person(int a,String n){
this(a);
this.name = n;
System.out.println("both!");
}
}
3.finalize方法
一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
public class FinalizeDemo{
public static void main(){
Cake c1 = new Cake(1);
Cake c2 = new Cake(2);
Cake c3 = new Cake(3);
c2 = c3 = null;
System.gc();//Invoke the Java garbage collector
}
}
class Cake extends Object{
private int id;
public Cake(int id){
this.id = id;
System.out.println("Cake Object "+id+" is created");
}
protected void finalize()throws java.lang.Throwable{
super.finalize();
System.out.println("Cake Object "+id+"is disposed");
}
}
/**
执行结果 :
Cake Object 1 is created
Cake Object 2 is created
Cake Object 3 is created
Cake Object 3 is disposed
Cake Object 2 is disposed
*/
4.在定义类成员变量的地方可以为其赋值,在C++中是不能这么做的。在类的内部,变量定义的先后顺序决定了初始化的顺序。
访问权限
1.package必须是文件中除注释以外的第一句程序代码。
2.每个文件只能有一个public类,但是也可以完全不带public类,在这种情况下,可以随意对文件命名。
3.类的名字必须与文件名相同.
4.除了public、private、protected之外,Java有一种默认的访问权限,当没有使用前面的访问指字词时,它将发挥作用。这种权限通常称为包访问权限。在这种权限下,同一个包中的类可以访问这个成员,而包之外的类,是不能访问这个成员的。
package testcontrol;
public class MyTest{
public int mIntPublic = 22;
protected int mIntProtected = 33;
private int mIntPrivate = 44;
int mInt = 55;
void printForAll()
{
System.out.println(mIntPublic);
System.out.println(mIntProtected);
System.out.println(mInt);
System.out.println(mIntPrivate);
}
}
package testcontrol;
//同一个包下的子类
class MyTestDerived extends MyTest
{
void printForAll()
{
System.out.println(mIntPublic);
System.out.println(mIntProtected);
System.out.println(mInt);
//Syste.out.println(mIntPrivate);
}
}
//同一个包下的非子类
public class MyTestNotDerived
{
public static main(String[] args){
MyTest objMyTest = new MyTest();
System.out.println("Access Permission Test in same package:1");
System.out.println(objMyTest.mIntPublic);
System.out.println(objMyTest.mIntProtected);
System.out.println(objMyTest.mInt);
//System.out.println(objMyTest.mIntPrivate);
System.out.println("Access Permission Test:2");
objMyTest.printForAll();
System.out.println("Access Permission Test in Derived:3");
objDerived.printForAll();
}
}
复用类
1.extends关键字用于类的继承。
2.在C++中,方法的动态绑定是使用virtual关键字来实现的,而在Java中,动态绑定是默认的形为,不需要添加额外的关键字。
//c++代码
class Base{
public :
Base(){init();}
virtual ~Base(){}
protected:
virtual void init()
{
cout<<"in Base::init()"<<endl;
}
};
class Derived:public Base{
public:
Derived(){init();}
protected:
void init(){
cout<<"in Derived::init()"<<endl;
}
};
int main(int argc,char* argv[]){
Base *pb;
pb = new Derived();
delete pb;
return 0;
}
/*
执行结果:
in Base::init()
in Derived::init()
*/
//java
class Base{
public Base(){init();}
protected void init(){
System.out.println("in Base::init()");
}
}
class Derived extends Base{
public Derived(){init();}
protected void init(){
System.out.println("in Derived::init");
}
}
public class Test{
public static void main(String[] args){
Base base = new Derived();
}
}
/*
执行结果 :
in Derived::init()
in Derived::init()
这是因为Java中的类对象在构造前就已经存在了,而c++中只有在构造完毕后才存在。
*/
3.使用关键字super显式调用基类的构造器。
4.final关键字
final可以修饰类、属性和方法。
(1)对于基本类型,final可以使其成为编译时常量,可以在定义时赋值,也可以在构造函数中进行赋值。
(2)对于对象引用,final使引用恒定不变,一旦引用被初始化指向一个对象,就无法再把它改为为指向另一个对象。
public class Bat{
final double PI = 3.14;//在定义时赋值
final int i;
final List<Bat> list;
Bat(){
i = 100;
list = new LinkedList<Bat>();
}
Bat(int ii,list<Bat> l){
i = ii;
list = l;
}
public static void main(String[] args){
Bat b = new Bat();
b.list.add(new Bat());
//b.i = 25;
//b.list = new ArrayList<Bat>();
}
}
(3)如果用final修饰方法,可以防止任何继承类修改它的含义。类中所有的private方法都隐式地指定为final。
(4)如果用final修饰类,表示不能再继承这个类。
(5)final修饰 的成员变量必须在声明的同时或在每个构造方法中显式赋值。
接口
1.用interface关键字创建一个接口,要让一个类实现特定接口,需要使用implements关键字。
2.接口也可以包含域,但是这些域隐式是static和final的。
interface Runner//定义接口
{
int i = 3;
public void start();
void run();
void stop();
}
interface Eater extends Runner//接口间可以继承
{
public final static int j = 4;
void openMouth();
void upAndDown();
void goIn();
}
class TT implements Eater//实现接口
{
public void start(){System.out.println("start");}
public void run(){System.out.println("run");}
public void stop(){System.out.println("stop");}
public void openMouth(){System.out.println("openMouth");}
public void upAndDown(){System.out.println("upAndDown");}
public void goIn(){System.out.println("goIn");}
}
public class TestInterface {
public static void main(String[] args){
Runner tt = new TT();
System.out.println(tt.i);
System.out.println(Runner.i);
tt.start();
Eater ee = new TT();
System.out.println(ee.j);
System.out.println(Eater.j);
ee.start();
}
}
内部类
在一个类中定义另外一个类,这个类就叫做内部类。
1.它能访问其外围对象的所有成员。
2.如果你需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟.this.
3. 使用.new创建内部类的引用
public Class Test(){
private int num;
public Test(int num){ this.num = num;}
private Class Inner{
public Test getTest(){
return Test.this;
}
public Test newTest(){
return new Test();
}
}
public static void main(String[] args){
Test test = new Test(5);
Test.Inner inner = test.new Inner();
Test test2 = inner.getTest();
Test test3 = inner.newTest();
System.out.println(test2.num);
System.out.println(test3.num);
}
}
/**
执行结果:
5 0
*/
类型信息
指程序能够在运行时发现和使用类型信息,我们一般使用两种方式来实现运行时对象和类的信息:传统的RTTI和反射机制。
1.class对象
专门用来保存类的信息,所有类都是动态加载到JVM中的,在他们第一次使用的时候,类加载器会首先检查Class对象是否加载,如果没有,那么找到同名的class文件,然后加载字节码文件,验证代码的完整性和安全性,一旦这个类型的class对象加载到内存中,它将会用来创建所有此类的对象。
class对象的生成方式如下:
(1)Class.forName(“类名字符串”)
(2)类名.class
(3)实例对象.getClass()
package Refect;
class Demo{
//other code...
}
class hello{
public static void main(String[] args){
Class<?> demo1 = null;
Class<?> demo2 = null;
Class<?> demo3 = null;
try{
demo1 = Class.forName("Reflect.Demo");
}cathc(Exception e){
e.printStackTrace();
}
demo2 = new Demo().getClass();
demo3 = Demo.class;
}
System.out.println("类名称 "+demo1.getName());//Reflect.Demo
System.out.println("类名称 "+demo2.getName());//Reflect.Demo
System.out.println("类名称 "+demo3.getName());//Reflect.Demo
}
2.instanceof
告诉我们对象是不是某个特定类型的实例。
3.反射
RTTI(运行时类型信息)和反射之间真正的区别只在于,对于RTTI来说,编译器在编译时打开和检查.class文件,而对于反射机制来说,.class文件在编译时是不可获取的,所以是在运行时打开和检查.class文件。
反射主要是指程序可以访问、检测和修改它本身或行为的一种能力。
package Reflect;
interface China{
public String name = "Rollen";
public int age = 20;
public void sayChina();
public void sayHello(String name,int age);
}
class Person implements China{
private String sex;
public Person(){};
public Person(String sex){this.sex = sex;}
public getSex(){return sex;}
public setSex(String sex){this.sex = sex;}
@Override
public void sayChina(){
System.out.println("hello, china");
}
@Override
public void sayHello(String name,int age){
System.out.println(name+" "+age);
}
}
class hello{
public static void main(String[] args){
Class<?> demo = null;
try{
demo = Class.forName("Reflect.Person")
}catch(Exception e){e.printStackTrace();}
//保存所有的接口
Class<?> intes[] demo.getInterfaces();
for(int i=0;i<intes.length;++i){
System.out.println("实现的接口 "+intes[i].getName());
//Reflect.China
}
//获得全部的构造函数
Constructor<?> cons[]= demo.getConstructors();
for(int i=0;i<cons.length;++i){
System.out.println("构造函数: "+cons[i]);
}
//通过反射调用其它类中的方法
try{
Method method = demo.getMethod("sayHello");
mehtod.invoke(demo.newInstance());
}catch(Exception e){e.printStackTrace();}
Object obj = null;
try{
obj = demo.newInstance();
}catch(Exception e){e.printStackTrace();}
//通过反射操作属性
Field field = demo.getDeclaredField("sex");
field.setAccessible(true);
field.set(obj,"男");
}
}
泛型
1.通配符
(1)通配符的上界
? extends myClass其中“?”就是通配符,其上界为myClass,这句话代表myClass或其子类。
List<Apple> apples = new ArrayList<Apple>();
List<? extends Fruit> fruits = apples;
(2)通配符的下界
? super myClass表示通配符的下界为myClass,这句话代表myClass的超类型直至Object。
List<Fruit> fruits = new ArrayList<Fruit>();
List<? super Apple> = fruits;
(3)无界通配符
?等价于Object。
注解
1.用于描述Java源代码,使得我们能够以将由编译器来测试和验证的格式,存储有关程序的额外信息。使用时在@后面跟注解的名字。
2.预定义的三个注解
(1)Override
标识某一个方法是否覆盖了它的父类的方法。
(2)Deprecated
标注一个类成员时,编译器会发出警告信息。
(3)SuppressWarnings
就是抑制编译器产生警告信息。
3.自定义注解
注解的定义和接口差不多,只是在interface前面多一个“
@”
public @interface MyAnnotation
{
}
上面的代码是个最简单的注解,这个注解没有属性。当然也可以定义有属性的注解。
public @interface MyAnnotation
{
String value();
}
可以按如下格式使用MyAnnotation
@MyAnnotation("abc")
public void myMethod()
{
}
这里有一个约定,如果没有写属性名的值,而这个注解又有value属性,就将这个值给value属性,如果没有,就出现编译错误。
除了可以省略属性名,还可以省略属性值,这就是默认值。
public @interface MyAnnotation
{
public String value() default "xyz";
}
可以直接使用MyAnnotation
@MyAnnotation
public void myMehtod()
{
}
4.元注解(对注解进行注解)
为注解提供了4种注解:
(1)Target
先看下面代码
@Target({ElementType.METHOD})
@interface MyAnnotation{}
@MyAnnotaion //wrong!
public class Class1
{
@MyAnnotation //right!
public void myMethod(){}
}
target所指的目标就是Java的语言元素,如类、接口、方法等。
(2)Retention
设置注解是否保存在class文件中
@Retention(RetentionPolicy.SOURCE)
@interface MyAnnotation{}
@Retention(RetentionPolicy.CLASS)
@interface MyAnnotation2{}
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{}
其中第一段代码的作用是不将注解保存在class文件中,也就是说像“//”一样在编译时被过滤掉了。第二段代码的作用是只将注解保存在class文件中,而使用反射读取注解时忽略这些注解。第三段代码的作用是将注解保存在class文件中,也可以通过反射读取注解。
(3)Documented
在默认的情况下使用javadoc自动生成文档时,注解将被忽略掉,如果想在文档中也包含注解,必须使用Documented为文档注解。
(4)Interited
在默认情况下,父类的注解并不会被子类继承,如果要继承,就必须加上Inherited注解。
@Inherited
@interface MyAnnotation{}
@MyAnnotation
public class ParentClass{}
public class ChildClass extends ParentClass{}
在以上代码中ChildClass和ParentClass一样都已被MyAnnotation注解。
5.使用反射读取注解
我们使用反射可以得到类的方法、方法的参数以及其它的类成员等信息。如果要得到某一个类或接口的注解信息,可以使用如下代码:
Annotation annotation = MyClass.class.getAnnotaion(MyAnnotation.class);
如果要得到全部的注解信息:
Annotation[] annotations = MyClass.class.getAnnotations();
或
Annotation[] annotations = MyClass.class.getDeclaredAnnotations();
getDeclaredAnnotations得到的是当前成员所有的注解,不包括继承。
并发
1.定义任务
线程可以驱动任务,因些你需要一种描述任务的方式,这可以由Runnable接口来提供。实现Runnable接口并编写run方法。~
2.Thread类
将Runnable对象转变为工作任务的传统方式是把它提交给一个Thread构选器。
3.join方法,某个线程加到另一个线程的“尾部”,当该线程执行完后,另一个线程再继续执行。
4.yield方法,当前运行的线程退出支行状态,会变成可运行状态,使同级别的线程有机会执行,但yield不能保证任何事情。
5.wait,调用wait必须拥有对象上的锁,wait可以释放锁,wait和notify必须要成对出现。
6.当调用对象的notify方法时,它会从当前对象的“wait set”中随机通知一个线程加入排队,被通知的线程会与其它正执行的线程共同竞争对象的“锁定”。
7.wait, notify, notifyAll是Object类提供的方法,而且它们都被声明为final。
8.
Runtime类和Process类
Runtime类封装了运行时的环境,每个Java应用程序都有一个Runtime类实例,使用应用程序能够与其运行环境相连接。通过Runtime.getRuntime()获取Runtime类的实例。Runtime类使用的是单例模式。
集合
(1)Collection接口的iterator和toArray方法都用于获得集合中的“所有元素”。前者返回一个“iterator”对象,后者返回一个包含集合中所有元素的数组。
(2)HashSet是基于Hash算法实现的,其性能通常优于TreeSet。在我们需要排序的功能时,我们才使用TreeSet。HashSet会调用对象的hashCode()方法来获得哈希码。
(3)ArrayList内部采用数组实现,LinkedList使用“链表”来实现。
(4)LinkedHashSet不仅实现了Hash算法,可以在迭代时,按照元素加入集合时的顺序来显示对象。
(5)TreeSet使用红黑树对元素进行排序。依靠TreeMap来实现。
(6)LinkedHashMap在迭代元素时,可以按照对象加入集合的顺序来显示。
(7)TreeMap可以使用红黑树来对键对象排序。和Set类似,HashMap的速度通常比TreeMap快,只有在需要排序的功能时,才使用TreeMap。
(8)Java提供了Arrays类来封装数组。
(9)历史集合类
Vector, Stack, Enumeration,Hashtable,Properties和BitSet。
由于Vector,Stack, Hashtable, Enumeration都使用了同步机制,并发性能差。Properties和BitSet由于有着特殊用途,所以不还常使用。
网络编程
1.TCP客户端程序与TCP服务器端程序的交互过程。
(1)服务器程序创建一个ServerSocket,然后调用Accept方法等待客户连接。
(2)客户端程序创建一个Socket并请求与服务器端建立连接。
(3)服务器接收客户的连接请求,并创建一个新的Socket与该客户建立专线连接。
(4)建立了连接的两个Socket在一个单独的线程(由服务器程序创建)上对话。
(5)服务器开始等待新的连接请求,当新的连接请求到达时,重得(2)~(5)。
2.TCP服务器程序编写
(1)调用ServerSocket()创建一个服务器端套接字,
(2)调用accept(),监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字。
(3)调用Socket类的getOutputStream()和getInputStream获取输出流和输入流,开始网络数据的发送和接收。
(4)最后关闭通信套接字。
3.客户端程序编写
(1)调用socket()创建一个流套接字,并连接到服务器端。
(2)调用socket类的getOutputStream()和getInputStream()获取输出流和输入流,开始网络数据的发送和接收。
(3)最后关闭通信套接字。
4.UDP接收端编写
(1)调用DatagramSocket(int port)创建一个数据报套接字,并绑定到指定的端口上。
(2)调用DatagramPackage(byte[] buf,int length),建立一个字节数组以接收UDP包。
(3)调用DatagramSocket类的receive(),接收UDP包。
(4)最后关闭数据报套接字。
5.发送端程序
(1)调用DatagramSocket()创建一个数据报套接字。
(2)调用DatagramPacket(byte[] buf, int length,InetAddress address,int port), 建立要发送的UDP包。
(3)调用DatagramSocket类的send(),发送UDP包。
(4)最后关闭数据报套接字。
数据库
1.JNDI
在J2EE容器中配置JNDI参数,定义一个数据源,也就是JDBC引用参数,给这个数据源设置一个名称,然后,在程序中通过数据源名称引用数据源从而访问后台数据库。
例子:
tomcatPath/conf/server.xml中的<GlobalNamingResources>节点中加入:
<Resource
auth="Container"
name="jdbc/oralce/jndi"
type="javax/sql/DataSource"<!-- jndi的接口驱动-->
driverClassName="oracle.jdbc.driver.OracleDriver"
username="test"
password="test"
maxIdle="5"
maxActive="30"
maxWait="5000"
url="jdbc:oracle:[email protected]:xxx"
/>
0条评论
qq_39744911