面向对象特征: 封装,继承,多态
封装:把属性隐藏,提供公共方法对其访问(private 封装特性的一种)
面向对象举例:利用对象的方法
面向过程:一步一步执行过程
静态变量、静态方法
- 静态变量:对象之间共享数据
- 静态方法:
- 静态方法只能访问静态成员[1],实例方法可以访问静态和实例成员。
- 调用静态方法可以无需创建对象(即"类名.方法名")
构造函数
作用:可以用于给对象进行初始化
默认构造函数的访问权限:
默认构造函数的访问权限和所属类一致
即:类被public修饰,那么默认构造函数也带public修饰(private同理)
构造函数与自定义函数区别:
写法上:
- 构造函数-无返回值
- 自定义函数-返回值可有可无
调用时机:
- 构造函数-对象创建是调用
- 自定义函数-由实例对象调用
main方法
- 必须定义为:public static void main(String args[]),这是Java的规范。
- 程序的入口,类被创建时,不会被调用
final关键字
final在Java中是一个保留的关键字,可以声明成员变量、方法、类以及本地变量。一旦你将引用声明作final,你将不能改变这个引用了,编译器会检查代码,如果你试图将变量再次初始化的话,编译器会报编译错误
final变量
只能赋值一次即可修饰成员变量,也可修饰局部变量
final变量经常和static关键字一起使用,作为常量。
final方法
方法前面加上final关键字,代表这个方法不可以被子类的方法重写。
如果你认为一个方法的功能已经足够完整了,子类中不需要改变的话,你可以声明此方法为final。final方法比非final方法要快,因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定。
final类
final类通常功能是完整的,它们不能被继承,被子类复写功能
Java中有许多类是final的,譬如String, Interger以及其他包装类。
final优点
- final关键字提高了性能。JVM和Java应用都会缓存final变量。
- final变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销。
- 使用final关键字,JVM会对方法、变量及类进行优化。
final的重要知识点
- final关键字可以用于成员变量、本地变量、方法以及类。
- final成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会报编译错误。
你不能够对final变量再次赋值。- final本地变量必须在声明时赋值。
- 在匿名类中所有变量都必须是final变量。
- final方法不能被重写。
- final类不能被继承。
- final关键字不同于finally关键字,后者用于异常处理。
- final关键字容易与finalize()方法搞混,后者是在Object类中定义的方法,是在垃圾回收之前被JVM调用的方法。
- 接口中声明的所有变量本身是final的。
- final和abstract这两个关键字是反相关的,final类就不可能是abstract的。
- final方法在编译阶段绑定,称为静态绑定(static binding)。
- 没有在声明时初始化final变量的称为空白final变量(blank final variable),它们必须在构造器中初始化,或者调用this()初始化。不这么做的话,编译器会报错“final变量(变量名)需要进行初始化”。
- 将类、方法、变量声明为final能够提高性能,这样JVM就有机会进行估计,然后优化。
- 按照Java代码惯例,final变量就是常量,而且通常常量名要大写
抽象类
在了解抽象类之前,先来了解一下抽象方法:
抽象方法是一种特殊的方法,它只有声明,而没有具体的实现。
抽象方法的声明格式为:
abstract void fun(); // 抽象方法必须用abstract关键字进行修饰
如果一个类含有抽象方法,则称这个类为抽象类
- 抽象类必须在类前用abstract关键字修饰
- 抽象类可以有构造函数(子类创建对象前被调用),但不能用抽象类创建对象,因为抽象类中含有无具体实现的方法
- 抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public
- 如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类
在其他方面,抽象类和普通的类并没有区别(可以拥有成员变量和普通的成员方法)。
接口
接口,英文称作interface,在软件工程中,接口泛指供别人调用的方法或者函数。从这里,我们可以体会到Java语言设计者的初衷,它是对行为的抽象。在Java中,定一个接口的形式如下:
[public] interface InterfaceName {
}
接口中可以含有 变量和方法。但是要注意:
- 接口中的变量会被隐式地指定为public static final变量(并且只能是public static final变量,用private修饰会报编译错误)
- 方法会被隐式地指定为public abstract方法且只能是public abstract方法(用其他关键字,比如private、protected、static、 final等修饰会报编译错误),并且接口中所有的方法不能有具体的实现,也就是说,接口中的方法必须都是抽象方法
从这里可以隐约看出接口和抽象类的区别,接口是一种极度抽象的类型,它比抽象类更加“抽象”,并且一般情况下不在接口中定义变量。
要让一个类遵循某组特地的接口需要使用implements关键字,具体格式如下:
class ClassName implements Interface1,Interface2,[....]{
}
可以看出:
- 允许一个类遵循多个特定的接口
- 如果一个非抽象类遵循了某个接口,就必须实现该接口中的所有方法。对于遵循某个接口的抽象类,可以不实现该接口中的抽象方法
抽象类和接口的区别
语法层面上的区别
- 抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的
- 接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口
- 抽象类不能被实例化,但可以有构造方法,接口中不能有构造方法
设计层面上的区别
单例模式
- 单例类只能有一个实例
- 单例类必须自己创建自己的唯一实例
- 单例类必须给所有其他对象提供这一实例
单例的实现
- 构造函数权限 private
- 对象是static属性 (保证内存只存一份)
- 接口 static
继承
如何使用继承体系中的功能
- 要使用体系,首先查阅体系父类的描述,因为父类中定义的是该体系中"共性功能"
- 通过了解共性功能,就可以知道该体系的基本功能。
为什么在具体调用时,要创建最子类的对象?
- 可能是因为父类不能创建对象
- 创建子类对象可以使用更多的功能,包括父类的+自己特有的
重写(也称覆盖)
- 子类覆盖父类权限 只能大于等于
- 静态只能覆盖静态 (生存周期不一样)
多态
多态指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
举个例子:
比方说按下 F1 键这个动作,如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;如果当前在 Word 下弹出的就是 Word 帮助;在 Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果。
多态存在的三个必要条件
- 要有继承
- 要有重写
- 父类引用指向子类对象
多态的好处
- 可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作
- 可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性
- 接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的
- 灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。
- 简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。
内部类
- 内部类可以直接访问外部类中的成员,包括私有
- 外部类要访问内部类,必须建立内部类对象
内部类访问格式
当内部类定义在外部类的成员位置上,且非私有。创建内部类的格式:
外部类名.内部类名 变量名 = 外部类对象.内部类对象;
Outer.Inter inter = new Outer.new Inter();
内部类定义在局部时:
- 不可以被成员修饰符修饰
- 可以直接访问外部类中的成员 //因为持有外部类中的引用
- 不可以访问它所在的局部中变量。只能访问被final修饰的局部变量
异常
严重问题Error类
非常严重问题Exception类
Throwable
Error
RuntimeException
Exception
异常信息打印
- e.getMessage() //打印异常信息
- e.toString() //异常名称+异常信息
- e.printStackTrace() //异常名称,异常信息,异常出现的位置(jvm默认异常处理机制就是调用 printStackTrace())
集合
List
有序,可重复
Set
无序,不可重复
Map
无序,key不可重复,value可重复
Iterator遍历的添加、删除
// 添加
List list = new ArrayList<String>();
Iterator it = list.iterator();
List<String> newList = new ArrayList<String>();
while(it.hasNext){
Object obj = it.next;
if(obj.equals('5')){
newList.add(obj);
}
}
list.addAll(newList)
// 删除
List list = new ArrayList<String>();
Iterator it = list.iterator();
while(it.hasNext){
Object obj = it.next;
if(obj == '5'){
it.remove();
}
}
加载顺序
静态变量、静态块——>main方法——>成员变量(匿名块属于成员变量)——>构造方法——>方法(静态、非静态)
同级的加载顺序由编写先后决定
public class test { //1.第一步,准备加载类
public static void main(String[] args) {
new test(); //4.第四步,new一个类,但在new之前要处理匿名代码块
}
static int num = 4; //2.第二步,静态变量和静态代码块的加载顺序由编写先后决定
{
num += 3;
System.out.println("b"); //5.第五步,按照顺序加载匿名代码块,代码块中有打印
}
int a = 5; //6.第六步,按照顺序加载变量
{ // 成员变量第三个
System.out.println("c"); //7.第七步,按照顺序打印c
}
test() { // 类的构造函数,第四个加载
System.out.println("d"); //8.第八步,最后加载构造函数,完成对象的建立
}
static { // 3.第三步,静态块,然后执行静态代码块,因为有输出,故打印a
System.out.println("a");
}
static void run() // 静态方法,调用的时候才加载// 注意看,e没有加载
{
System.out.println("e");
}
}
存在继承关系时的加载顺序
public class Print {
public Print(String s){
System.out.print(s + " ");
}
}
public class Parent{
public static Print obj1 = new Print("1");
public Print obj2 = new Print("2");
public static Print obj3 = new Print("3");
static{
new Print("4");
}
public static Print obj4 = new Print("5");
public Print obj5 = new Print("6");
public Parent(){
new Print("7");
}
}
public class Child extends Parent{
static{
new Print("a");
}
public static Print obj1 = new Print("b");
public Print obj2 = new Print("c");
public Child (){
new Print("d");
}
public static Print obj3 = new Print("e");
public Print obj4 = new Print("f");
public static void main(String [] args){
Parent obj1 = new Child ();
Parent obj2 = new Child ();
}
}
执行main方法,程序输出顺序为: 1 3 4 5 a b e 2 6 7 c f d 2 6 7 c f d
输出结果表明,程序的执行顺序为:
如果类还没有被加载:1、先执行父类的静态代码块和静态变量初始化,并且静态代码块和静态变量的执行顺序只跟代码中出现的顺序有关。
2、执行子类的静态代码块和静态变量初始化。
3、执行父类的实例变量初始化
4、执行父类的构造函数
5、执行子类的实例变量初始化
6、执行子类的构造函数如果类已经被加载:
则静态代码块和静态变量就不用重复执行,再创建类对象时,只执行与实例相关的变量初始化和构造方法。
网络编程
UDP
将数据及源和目的封装在数据包中,区需要建立连接
每个数据报的大小限制在64K内
因无连接,是不可靠协议
不需要建立连接,速度快
TCP
建立连接,形成传输数据的通道
在连接中进行大数据量传输
三次握手,是可靠协议
必须建立连接,效率会稍低
-
之所以不允许静态方法访问实例成员变量,是因为实例成员变量是属于某个对象的,而静态方法在执行时,并不一定存在对象。同样,因为实例方法可以访问实例成员变量,如果允许静态方法调用实例方法,将间接地允许它使用实例成员变量,所以它也不能调用实例方法。基于同样的道理,静态方法中也不能使用关键字this` ↩