1、Java语言的优点
- Java为纯面向对象语言。
- 平台无关性,一次编译,到处运行。(Java为解释型语言,编译器会把Java代码编程字节码,然后在虚拟机上解释执行)
- Java内置很多类库,多线程,网络编程,垃圾回收等
- 提供对Web应用开发的支持
- 具有较好的安全性(数组边界检测,Bytecode校验)和健壮性(强制类型机制,垃圾回收器,异常处理,安全检查机制)
- 去除了C++难以理解的、容易混淆的部分(头文件,指针,结构,单元,运算符重载,虚拟基础类,多重继承)
2、Java与C++对比
- Java为解释性语言,Java执行速度慢,但是可以跨平台
- Java为纯面向对象语言,除基本数据类型外,所有类型都是类
- Java语言中没有指针的概念
- Java语言不支持多继承
- Java语言提供垃圾回收器实现垃圾自动回收,不需要程序显式地管理内存分配(当垃圾回收器将要释放无用的对象时,首先会调用该方法的finalize()方法)
- Java不支持运算符重载、没有预处理器,不提供goto(goto为保留字),不能自动类型转换,必须显式强制类型转换
- Java具有平台无关性,每种数据类型都分配固定的长度(byte 1字节、char 2字节、short 2字节、int 4字节(默认)、long 8字节、float 4字节、double 8字节(默认))
- Java对注释文档的内建支持、包含标准库(如访问数据库的JDBC和实现分布式对象的RMI等)
3、public static void main(String[] args){}
Java程序的入口,JVM运行程序时,会首先查找main方法
- public : 任何类和对象都可以访问这个方法
- stastc : main是一个静态方法,方法中的代码是存储在静态存储区的,只要类被加载了就可以使用main方法,不徐娅需要实例化对象来访问
- 可以直接通过类名.mian()进行方法的访问
- args : 字符串数组为开发人员在命令行状态下与程序交互的一种手段
要执行一个类的方法,必须先实例化一个对象,然后通过对象来调用这个类的方法
同一个.java文件中每个类都可以定义main()方法,但是只有与文件同名的用public修饰的类中的main()方法才是整个程序的入口
public class test{
static {
System.out.println(“Hello”);
}
public static void mian(String[] args){
System.out.println(“world”);
}
}
static修饰的静态代码块在类被加载时就会被调用,因此可以在main()方法执行前,利用静态块实现初始化或输出功能(静态代码块无论位置如何都在main()之前执行)
4、Java程序初始化顺序
当实例化对象时,对象所在的类的所有成员变量首先要进行初始化,只有当所有类成员完成初始化后,才会调用对象所在类的构造函数创建对象
Java程序初始化一般遵循3个原则(优先级依次递减):
- 静态对象(变量)优先于非静态对象(变量),静态对象(变量)指只初始化一次,非静态对象(变量)可能会初始化多次
- 父类优先于子类初始化
- 按照成员变量的定义顺序进行初始化(即使变量定义散布在方法定义之中,他们依然在任何方法,包括构造函数,被调用之前先初始化)
优先级递减 |
---|
父类静态变量 |
父类静态代码块 |
子类静态变量 |
子类静态代码块 |
父类非静态变量 |
父类非静态代码块 |
父类构造函数 |
子类非静态变量 |
子类非静态代码块 |
子类构造函数 |
5、Java中的作用域
作用域由花括号的位置决定,它决定了其定义的变量名的可见性和生命周期
变量分为三种:
- 成员变量
- 静态变量(全局变量,被所有实例所共享,只要类一被加载,JVM就会给类的静态变量分配存储空间)
- 局部变量
作用域的可见性(修饰符只能修饰成员变量,不能修饰局部变量,private和protected不能修饰包):
作用域与可见性 | 当前类 | 当前包 | 子类 | 包外 |
---|---|---|---|---|
public | Y | Y | Y | Y |
protected | Y | Y | Y | |
default | Y | Y | ||
private | Y |
default : 如果父类和子类在同一个包中,子类对父类的default成员变量和方法是可以访问的,不在一个包中,则不行
一个Java文件中可以定义多个类,但是最多只能有一个类被public修饰,并且这个类的名称与文件名必须相同,若这个文件中没有public的类,则文件名随便是一个类的名字就可以了,javac编译时,会生成每一个类的对应的.class文件
6、构造函数
构造函数是一种特殊的函数,用来在对象实例化时初始化对象的成员变量
- 构造函数必须以类名相同,且不能有返回值(不是void)
- 每个类可以有多个构造函数,每个构造函数可以有若干个参数
- 构造函数总是伴随着new 操作一起调用
- 构造函数的主要工作时完成对象的初始化
- 构造函数不能被继承(即不能被重写),但是可以被重载
- 子类可以通过super()显示调用父类的构造函数
- 父类和子类都没有构造函数时,编译器会自动添加无参构造函数(此构造函数的修饰符只跟当前类的修饰符有关)
- 普通方法可以与构造方法有相同的方法名
当父类没有提供无参的构造函数时,子类的构造函数中必须显式调用父类的构造函数
父类提供无参构造函数时,子类构造函数可以不显式调用父类的构造函数,编译器会默认调用父类的无参构造函数
7、标识接口
- 接口是抽象方法定义的集合(接口中也可以定义常量),是一种特殊的抽象类
- 接口中只包含方法的定义,没有方法的实现
- 没有任何方法声明的接口叫做标识接口,仅仅充当一个标识的作用,用来表明实现它的类属于一个特定的类型(Cloneable Serizlizable等)
在使用时经常用instanceof判断一个实例是否实现了一个给定的标识接口
8、Java中clone方法的作用
实质上,每个new语句返回的都是一个指针的引用,往往我们忽略了对象和引用的区别
Java中的函数参数传递:
- 基本类型时采用的是值传递(传递的是输出参数的复制)
- 其他类型都是按引用传递(传递的是对象的一个引用)
对象除了在函数传递的时候是引用传递,在使用=赋值的时候也是引用传递
Java中的所有类都默认继承自Object类,其中提供一个clone()方法,该方法返回一个Object对象的复制(这个方法返回的是一个新对象,而不是一个引用)
clone方法的使用:
- 类需要实现Cloneable接口
- 在类中重写Object类的clone()方法
- 在clone()方法中调用super.clone()
- 把浅复制的引用指向原型对象新的克隆体
- 对对象调用clone()方法完成复制后,对对象中的非基本类型的属性也调用该对象的clone()方法完成深复制
当类中只有基本数据类型时,以上步骤1-4就可以了,但是当类中包含一些对象时,需要进行深复制
深复制与浅复制的区别:
- 深复制:被复制对象的所变量都含义与原来对象相同的值,那些引用其他对象的变量将指向被复制的新对象,而不再是原来的那些被引用的对象
- 浅复制:被复制对象的所变量都含义与原来对象相同的值,所有对其他对象的引用任然指向原来的对象
class Obj implements Cloneable{
private int age =0;
private Date birth = new Date();
public void getBirth(){
return birth;
}
public Object Clone(){
Obj o = null;
try{
o = (Obj)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace():
}
o.birth = (Date) this.getBirth().clone();
return 0;
}
}
9、反射机制
反射机制能够实现在运行时对类进行装在因此能够增加程序的灵活性,主要提供如下功能:
- 得到一个对象所属的类
- 获取一个类的所有成员和方法
- 在运行时动态地创建对象(非常重要的作用)
- 在运行是调用对象的方法
取得Class类的3种方法:
- Class.forName(“类路径”)
- 类名.Class
- 实例.getClass()
创建对象的4种方法:
- 通过new语句实例化一个对象
- 通过反射机制创建对象
- 通过clone()方法创建对象
- 通过反序列化创建对象
10、在Java中实现类似于函数指针的功能
- 定义一个接口
- 在接口中声明调用方法
- 实现这个接口
- 把接口的这个实现类的一个对象作为参数传递给调用程序
- 调用程序通过这个参数来调用指定的函数,从而实现回调函数的功能