您的位置:首页 > 编程语言 > Java开发

java中容易犯错的知识点

2016-05-27 18:56 543 查看

java中容易犯错的知识点

该博客的内容是在看了《head first java》之后总结的一些知识点,是针对我个人的不足总结的知识点,我写博客还是newer,希望大神们多多指教。需要注意的是这篇内容的标号和《head first java》中的章节标号不是一致的。


目录

java中容易犯错的知识点

目录

No1 对象数组

No2 java中的修饰符的访问权限

No3 局部变量与实例变量

No4 C与JAVA中创建对象的不同

No5 变量的比较

No6 和的区别

No6 JAVA 中的多态

No7 抽象的方法和类

No8 构造器和垃圾收集器

No9 静态static

No10 基本数据类型的包装autoboxing

No11 图形用户接口

No12 保存对象序列化

No13 网络与线程
一 网络联机

二 线程的建立过程

三 多线程并发性死锁预防

No14 集合与泛型

No15 远程部署

No.1 对象数组

我曾经在一家公司实习的时候,学习的是C#。虽然都是C类语言,但其实它和JAVA的语法之类的更为匹配一些,当时初学的时候就范了一个错误:

class Dog{
String  name;
Dog(String na){
name = na;
}
public void setName(String na){
name = na;
}
public String getName(){
return name;
}
}

public class DogTest{
public static void main(String[] args){
Dog[] dog = new Dog[7];
}
}


上面的这段代码你知道哪儿错了吗?解答如下:





就像买东西的时候一般都是从口袋里面拿出钱包,再从钱包里面拿出钱。这个钱包就相当于一个引用,但是如果你钱包里面没钱,即使你有钱包也买不到东西(当然,要是老板同意让你拿钱包抵押,那是另外一回事了。。。)。所以 Dog[] dog = new Dog[7];这句代码只相当于你得到了钱包,但是不幸的是钱包里面并目前钱(即对象),所以需要放点钱进去 dog[0] = new Dog(“man”);

No.2 java中的修饰符的访问权限

C++和java都是面向对象的,但是呢,我个人觉得真正的面向对象是JAVA。虽然大学四年都在和C++打交道,但是连《C++primer》都没看过的我来说,很多知识点是懵的。BUT,我还是先来整理一下关于JAVA的好啦。

需要注意的是:在java中类的成员变量默认为default ,但是在C++中默认为private。

修饰符权限表格如下:

访问权限同一个包子类其它包
public
protected×
default××
private×××
同时还有类的其它两个修饰符abstract (修饰的类只声明方法,并不实现)、final(修饰的类不能被继承)

No.3 局部变量与实例变量

局部变量是某个方法的参数或者内部需要时候才声明的变量,这个时候局部声明的变量必须初始化才能使用,但是类中的实例变量不需要在声明的时候初始化。Eg:

class Test{
String name;
public void go(){
String test;
name = name + "right"; //可以通过
test = test + "wrong";//this is wrong!!!必须初始化,因为局部变量没有默认值。
}
}


No.4 C++与JAVA中创建对象的不同

毕竟我大学四年搬运的代码都是C++的,所以还是需要对比一下两者的不同。JAVA中已经木有了指针的这个概念,其实java中的引用在某些地方是可以替代C++中的指针的作用的。

C++中创建对象

1. Test test;//在栈中
2. Test* test = new Test();
delete(test);//分配的内存在堆中,因为C++中木有GC,所以这种创建对象的方式需要手动删除对象
class Test{
String name;
}


JAVA中创建对象的方式:

Test test = new Test();//分配的内存是在托管堆中,因此并不需要手动删除对象。test是对托管堆中对象的引用。


No.5 变量的比较

使用“==”来比较两个基本类型,或者判断两个引用是否指向同一个对象。因为”==”比较是是字节组合

使用equals()来判断两个对象是否在意义上相等

No.6 & 和&&的区别

虽然&和&&都是逻辑运算符,但是在运行的时候会有差别。

两者的差别如下:

System.out.println(false & (1/0 == 0));//这句话会抛出异常,因为除数不能为零
System.out.println(false && (1/0 == 0));//这句话会打印出false


Note:这两句话的不同只在于运算符的不同,所以这说明:&运算符会判断左右两边所有条件,但是&&运算符如果前者能决定结果,那么后面的就可以不用判断了。

No.6 JAVA 中的多态

可以参考java学习之多态,这篇文章写得比《head first java》中清楚得多,毕竟我觉得《head first java》这本书的中文版翻译还是存在很多问题的。总结来说呢,java多态需要注意以下几点:

1. 覆盖属于多态,但是函数重载(不能只改变返回类型)不属于多态。

2. 多态==晚绑定,因为多态是一种运行期的行为,不是编译期的行为

3. 当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如:

class Animal{
String name;
public void eat(){
//eat food;
}
}
class Cat extends Animal{
public void makeNoise(){
//make cat noise;
}
public void eat(){
//Cat eat;
}
}

class Dog extends Animal{
public void eat(){
//Dog eat;
}
}

//main
class Test{
public static void main(String[] args){
//向上类型转换
Cat cat = new Cat();
Animal animal = cat;
animal.eat();//right,eat()函数在animal类中也存在,但是       调用的是Cat的eat()函数。
animal.makeNoise();//wrong ,makeNoise()不存在父类中
//向下类型转换
Animal animal = new Cat();
animal.makeNoise();//wrong,makeNoise()在animal父类中不存在。
Cat cat = (Cat)animal;
cat.eat();
cat.makeNoise();//right,调用cat中的makeNoise()函数。
}
}


总结就是:可以用父类代表子类。

No.7 抽象的方法和类

抽象的类中可以有static 的成员,抽象与非抽象的方法;(static修饰的变量表示一个类有且仅有一个,有种全局的感觉)

不能在非抽象的类中拥有抽象的方法,也就是要是一个类有抽象的方法,该类必是抽象类;

抽象的类表示一定要被extends;

No.8 构造器和垃圾收集器

关于构造器,主要有以下几点:

1. 在创建新对象的时候,所以继承下来的构造函数都会执行,也就是父类的构造函数都会执行一遍。

2. 某个类的构造函数若修饰符是private,那么代表这个类不能被实例化。

3. 使用this()来从某个构造函数调用同一类的另外一个构造函数,this()只能用在构造函数中,且必须是第一行语句,super()(对父类构造函数的调用)与this()不能兼得。例如 :

class Cat extends Animal{
Color color;
public Cat(){
this(Color.red);//对该类中的下一个构造函数进行调用
}
public Cat(Color c){
super("Cat");//对父类构造函数的调用
color = c
}
}


关于垃圾收集器,java虚拟机的GC机制可以自动回收托管堆中的对象,至于进行回收的算法,那是另外一件事情啦。

No.9 静态static

类中的静态变量对所有的实例都是相同的。

static final double PI = 3.14,final代表不可变的。

静态的方法不能调用非静态的变量,因为它并不知道这个非静态的变量是属于哪个实例的。

Java中会把常量标记为 final和static的,必须在声明或者静态初始化中赋值。两种如下:

1.
pubic class FOO{
public static final int FOO_X = 25;
}
2.
public class FOO{
public static final int FOO_X;
static{
FOO_X = (int)Math.random();
}
}


No.10 基本数据类型的包装——autoboxing

因为有些时候想把基本数据类型当做对象来处理,就需要对其进行包装,解包。Java5.0之后就加入了autoboxing

//无autoboxing
public void doNum(){
ArrayList listNum = new ArrayList();
listNum.add(new Integer(3));//不能直接加入3,得先转为对象
Integer one = (Integer)listNum.get(0);//返回Object类型,转为Integer类
int intOne = one.intValue();
}

//有autoboxing
public void doNum(){
ArrayList<Integer> listNum = new ArrayList<Integer>();
listNum.add(3);//直接加入3,编译器自动装包
int one = listNum.get(0);//编译器自动完成解包


No.11 图形用户接口

Question: 当每个按钮执行不同工作时,要如何对多个不同的按钮分别取得事件?

Answer: 内部类!!内部类可以外部类的所有方法和变量。内部类的实例一定会绑定在外部类的实例上。

内部类与外部类的关系如下:



监听GUI事件:



Notice:非静态内部类的实例必须通过外部类的实例才能获得,但是对于静态的内部类不需要外部类的实例就可以调用,但是静态内部类只能调用外部类的静态变量。

Question:当你在编写GUI程序的时候,突然发现你需要实现一个ActionListener的类的实例,但是你发现你没有任何该类的实例,之前也没有写个该类,那你该怎么做呢?

Answer:一是在程序中实现内部类,二是当场创建出匿名的内部类。如下:

public class test{
public static void main(String[] args){
JFrame frame = new JFrame();
JButton button = new JButton("click");
frame.getContentPane().add(button);
//  button.addActionListener(quitListener);//通常是传入一个内部类的实例
buttton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
System.exit(0);
}});//现场定义了一个类,并且创建了它的实例。
}
}


No.12 保存对象(序列化)

要存储对象的状态,有两种办法:一. 写入纯文本文件;二. 将其进行序列化。

要让类能够被序列化,必须实现Serializable

static不会被序列化,如果某个变量不想被序列化,就标记为transient。

进行序列化代码如下:

//序列化到文件
FileOutputStream fileStream = new FileOutputStream("my.ser");
ObjectOutputStream os = new ObjectOutputStream(fileStream);
os.writeObject(one);
os.close();

//解序列化
FileInputStream fileStream = new FileInputStream("my.ser");
ObjectInputStream os = new ObjectInputStream(fileStream);
Object one = os.readObject();
Game two = (Game)one;
os.close();


No.13 网络与线程

一. 网络联机

java中也是通过Socket进行网络的连接,连接图如下:



public class DailyAdvice{
public void go() {
try {
Socket sock = new Socket("127.0.0.1", 5555);//建立连接
InputStreamReader streamReader = new InputStreamReader(sock.getInputStream());//用StreamReader读取服务器传过来的内容。
BufferedReader reader = new BufferedReader(streamReader);

String advice = reader.readLine();

reader.close();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
public static void main(String [] args) {
DailyAdvice client = new DailyAdvice();
client.go();
}
}


二. 线程的建立过程

public class MyRunnable implements Runnable{
public void run() {//必须要实现,这是thread运行所需执行的任务
go();
}

public void go() {
doMore();
}

public void doMore() {
System.out.println("something");
}
}

class ThreadTester{
public static void main(String [] args) {
MyRunnable job = new MyRunnable();
Thread th = new Thread(job);
th.start();//开启线程
}
}


一旦线程进入可执行状态,就会在可执行和执行中两种状态切换。

三. 多线程,并发性、死锁预防

线程的并发性会导致致命的错误,所以必须对一部分代码进行同步化。即用synchronized这个关键字来修饰方法使其每次只能被一个线程调用。事实上,每个对象,每个类都会有一个锁,同步化就是把锁变成有用的工具。当然也可以只同步化需要同步化的几行代码:

public void go(){
synchronized(this){//需要同步化的代码
//critical stuff
}
}


当然多线程也会发生死锁,所以要避免死锁。

多线程的实例

//服务端程序
public class ChatServer {
ArrayList clientOutputStream;
public class ClientHander implements Runnable{
BufferedReader reader;
Socket sock;

public ClientHander(Socket clientSocket) {
try {
sock = clientSocket;
InputStreamReader isReader = new InputStreamReader(sock.getInputStream());
reader = new BufferedReader(isReader);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}

public void run() {//thread会运行的程序
String message;
try {
while((message = reader.readLine()) != null) {
System.out.println("read "+ message);
tellEveryone(message);
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
public void go() {
clientOutputStream = new ArrayList();
try {
ServerSocket server = new ServerSocket(5006);

while(true) {
Socket clientSock = server.accept();
PrintWriter writer = new PrintWriter(clientSock.getOutputStream());
clientOutputStream.add(writer);

Thread t= new Thread(new ClientHander(clientSock));
t.start();//会产生新的线程
System.out.println("got a connection");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}//end go
public void tellEveryone(String message) {
Iterator it = clientOutputStream.iterator();
while(it.hasNext()) {
try {
PrintWriter writer = (PrintWriter)it.next();
writer.println(message);
writer.flush();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}

//main
public static void main(String[] args) {
new ChatServer().go();
}
}


No.14 集合与泛型

1 . 集合中的关系如下图:



2. 当使用compareTo()函数的时候,list中只可以有一个将自己与同类型比较的方法。所以可以使用comparator这个独立的类,自制比较函数。如下:



泛型

下面两个方法的声明

public void eat(ArrayList list){}

public void eat(ArrayList list){}

前者可以使用任何的animal,如可以使用ArrayList作为参数传递,但是后者只有ArrayList才是合法的。与第一句相同功能的声明如下:

public void eat(ArrayList

No.15 远程部署

其实这部分看到后面就没力气了,所以先放一放,等我看完再来更新好啦!(谁可以告诉我:怎么才能充满power~)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 博客