复习第二天
以下内容参考了《Java编程思想 第四版》 《疯狂Java 第二版》
1.类和对象
定义类
- Java类名必须是由一个或多个有意义的单词连缀而成,每个单词首字母大写,其他字母全部小写,单词与单词之间不要使用任何分隔符。
- 类的组成部分:构造器,属性,方法,初始化代码块,内部类(包括接口,枚举)等等。类里各成员定义的顺序没有影响。
- 创建对象的根本途径是构造器,通过new关键字来调用某个类的构造器即可创建这个类的实例。
this关键字
- this关键字总是指向调用该方法的对象。
- this():可以调用构造方法,必须位于构造方法的第一行。
2.方法
- 方法不能独立定义,方法只能在类体里定义。
- 从逻辑意义上看,方法要么属于该类本身,要么属于该类的一个对象。
- 永远不能独立执行方法,执行方法必须使用类或对象作为调用者。
递归方法
- 一个方法体内调用他自身,被称为方法递归 。
- 方法递归相当于隐式循环,他会重复执行某段代码,但是无需循环控制。
已知有一个数列:f(0)=1,f(1)=4,f(n+2)=2*f(n+1)+f(n),求 f(10).
/**
* 递归方法
* @author lw
* */
public class Test03 {
public static void main(String[] args) {
System.out.println(fn(10));
}
public static int fn(int n) {
if (n == 0) {
return 0;
} else if (n == 1) {
return 4;
} else {
return 2 * fn(n - 1) + fn(n - 2);
}
}
}
方法重载
- 方法名相同;
- 参数列表不同(参数个数不同或者参数类型不同);
- 重载与返回值没有关系,与修饰符没有关系;
- 重载发生在同一个类中(继承中也有重载);
/**
* 方法重载
*
* @author lw
*
*/
public class Test04 {
public void method(int i, int b) {
System.out.println(i + b);
}
public double method(double a, int b) {
return a + b;
}
private void method(int a) {
System.out.println(a);
}
}
构造器
- 作用:用于创建实例时执行初始化。
- 构造器名字与类名一样。
- 如果写的类里面没有构造器,编译器会自动创建一个默认的构造器。
- 构造器可以重载。
- 构造器中可以用this关键字调用另一个构造器。
static关键字
- static方法就是没有this的方法;
- 在static方法的内部不能调用非静态方法,反过来可以。
- 无论创建多少个对象,静态数据都只占用一份存储区域。
3.面向对象
- 面向对象三大特征:封装、继承、多态。
封装
- 将对象的属性和实现细节隐藏起来,不允许外部直接访问。
- 暴露方法,让方法来控制对这些属性进行安全的访问和操作。
- 类是对属性和方法的封装,方法是对代码的封装。
访问修饰符
- public 接口访问权限
- 声明自己对每个人都是可用的。
- default 包访问权限
- 同一个包中可以访问
- private 无法访问
- 除了包含该成员的类之外,其他任何类都无法访问这个成员。
- protected 继承访问权限
- 继承关系可访问
. | 同一个类中 | 同一个包中 | 子类 | 同一个项目 |
---|---|---|---|---|
private | ok | |||
default | ok | ok | ||
protected | ok | ok | ok | |
public | ok | ok | ok | ok |
继承
- 继承用extends关键字来实现,实现继承的类被称为子类。
- 使用继承可以减少代码量,扩展方便。
- 一个类只能有一个直接父类,但可以有多个子类。
- 所有类都是Object类的子类。
class A {
}
class B extends A {
}
class C extends A {
}
class D extends C {
}
子类不能继承父类的成员
- private修饰的
- 父类使用默认修饰权限,字类和父类不同包。
- 构造方法不能被继承。
重写父类的方法
- 方法名相同
- 方法的访问修饰符不能严与父类
- 返回值类型要和父类相匹配
- 方法的参数列表要和父类相同(不同则是方法重载)
- 子类不能抛出比父类多的异常
class A {
public void method(int i) {
System.out.println(i);
}
}
class B extends A {
// 方法重写
@Override
public void method(int i) {
System.out.println(i);
}
// 方法重载
public void method(int i, double b) {
System.out.println(i + b);
}
}
super关键字
- 在子类中调用父类的被覆盖的实例方法,用super关键字。
- 当调用子类构造器来初始化子类对象时,父类构造器总是在子类构造器之前执行
/**
* output : A 无参数构造器
* B 一个参数构造器 a= 10
* B 两个参数构造器 a=10str...aaa
* C 无参数构造器
*
* @author lw
*
*/
public class Test06 {
public static void main(String[] args) {
new C();
}
}
class A {
public A() {
System.out.println("A 无参数构造器");
}
}
class B extends A {
public B(int a) {
System.out.println("B 一个参数构造器 a= " + a);
}
public B(int a, String str) {
this(a);
System.out.println("B 两个参数构造器 a=" + a + "str..." + str);
}
}
class C extends B {
public C() {
super(10, "aaa");
System.out.println("C 无参数构造器");
}
}
多态
- 多态是一项让程序员“”将改变的事物与未变的事物分开“”的重要技术
/**
* output : 父类方法
* 子类方法
*
* @author lw
*
*/
public class Test07 {
public static void main(String[] args) {
Parent p1 = new Parent();
Parent p2 = new Child();
p1.method();
p2.method();
}
}
class Parent {
public void method() {
System.out.println("父类方法");
}
}
class Child extends Parent {
@Override
public void method() {
System.out.println("子类方法");
}
}
- 相同类型的变量,调用同一个方法时呈现不同的行为特征,这就是多态。
- 如何产生多态:
- 继承关系下
- 要有方法重写
- 父类引用指向子类对象
- 构造器不存在多态性
- 如果某个方法是静态的,它的行为不存在多态:
public class TestStatic {
public static void main(String[] args) {
Parent p = new Child();
p.method();// output: 父类静态方法
p.test();// output:子类普通方法
}
}
class Parent {
public static void method() {
System.out.println("父类静态方法");
}
public void test() {
System.out.println("父类普通方法");
}
}
class Child extends Parent {
public static void method() {
System.out.println("子类静态方法");
}
@Override
public void test() {
System.out.println("子类普通方法");
}
}
instanceof关键字
- 前一个操作数通常是一个引用类型变量,后一个通常是一个类或者接口。
Object str="aa";
System.out.println(str instanceof Object);
4.初始化
package com.lwcode.ui;
public class Test05 {
public static void main(String[] args) {
/*
* Aa 的静态初始化快
Bb 的静态初始化块
Cc 的静态初始化块
Aa 的普通初始化块
Aa 的无参数构造器
Bb 的普通初始化块
Bb 的无参数构造器
Bb 的有参数构造器
Cc 的普通初始化块
Cc 的无参数构造器
*/
new Cc();
/*
* Aa 的普通初始化块
Aa 的无参数构造器
Bb 的普通初始化块
Bb 的无参数构造器
Bb 的有参数构造器
Cc 的普通初始化块
Cc 的无参数构造器
*/
new Cc();
}
}
class Aa {
static {
System.out.println("Aa 的静态初始化快");
}
{
System.out.println("Aa 的普通初始化块");
}
public Aa() {
System.out.println("Aa 的无参数构造器");
}
}
class Bb extends Aa {
static {
System.out.println("Bb 的静态初始化块");
}
{
System.out.println("Bb 的普通初始化块");
}
public Bb() {
System.out.println("Bb 的无参数构造器");
}
public Bb(int a) {
// 调用自己无参数构造器
this();
System.out.println("Bb 的有参数构造器");
}
}
class Cc extends Bb {
static {
System.out.println("Cc 的静态初始化块");
}
{
System.out.println("Cc 的普通初始化块");
}
public Cc() {
// 调用父类有参构造器
super(1);
System.out.println("Cc 的无参数构造器");
}
}
- 初始化的顺序
- 静态初始化块–>普通初始化块–>构造器
- 静态初始化块只执行一次
5.==和equals方法
- ==:如果两个操作数都是基本类型,且都是数值类型,只要两个变量的值相等,就返回true;(==判断的是数值大小)
- 如果两个都是引用类型,它们必须指向同一个对象时,==才会返回true;(==判断的是地址是否一致)
- equals方法:可以自己重写equals方法来定义相同的标准。Object类默认提供的equals方法比较的是对象的地址。
6.final关键字
final修饰属性
- final修饰的变量为常量,必须赋初值,这个值不能被改变。
- 一般为了常量使用的便利性,会用static修饰
- final修饰的是基本数据类型,则不可以改变基本数据类型的值
- final修饰的是引用类型,则不可以改变引用类型的地址
- 常量的命名规则:所有字母大写,单词之间用下划线分隔
final修饰方法
- 把方法锁定,防止任何继承类修改它的定义
- 确保在继承中使方法行为保持不变,并且不会被覆盖
final修饰类
- final修饰的类不能被继承,比如String类,Class类,StringBuffer等
7.abstract关键字
- 抽象类必须用abstract修饰符修饰,抽象方法也必须用abstract修饰符修饰,抽象方法没有方法体
- 抽象类不能被实例化,不能用new关键字来调用抽象类的构造器创建抽象类的实例。(抽象类里不包含抽象方法也不能创建实例)
- 抽象类组成:属性,方法,构造器,初始化块,内部类,枚举。构造器不能用于创建实例,主要用于被子类调用。
- 含有抽象方法的类只能被定义成抽象类。
- 子类继承抽象类,则必须重写这个类的所有抽象方法,否则这个子类也必须是抽象类。
8.interface关键字
使用接口的好处
- 接口可以避免Java继承的单根性,一个接口可以继承多个接口
- 接口更加容易实现多态
- 接口更加容易搭建框架
接口的组成
- 接口中只能存放常量和抽象方法
- 常量默认采用public static final 修饰
- 方法默认采用public abstract 修饰
使用接口
- 接口不能创建实例,但接口可以用于声明引用类型变量。
- 很多软件架构设计理论都倡导“面向接口”编程。
9.单例设置模式
public class PersonTest {
public static void main(String[] args) {
Person p1 = Person.getPerson();
Person p2 = Person.getPerson();
//输出为true 表明创建的是同一个对象
System.out.println(p1 == p2);//output : true
}
}
class Person {
// 该变量用来存储之前创建的实例
private static Person person;
// 构造器采用private修饰,隐藏起来
private Person() {
}
/*
* 该静态方法用来返回Person实例 加入控制条件保证只产生一个Person实例
*
*/
public static Person getPerson() {
/*
* person为null,表明之前还没有创建Person对象
* person不为null,表明之前已经创建了Person对象,则不再创建新的Person对象
*/
if (person == null) {
person = new Person();
}
return person;
}
}
10.代理模式
/**
* 抽象主题
*
* @author lw
*
*/
public interface Subject {
void method();
}
/**
* 真实类
*
* @author lw
*
*/
public class Player implements Subject {
@Override
public void method() {
System.out.println("真实类方法");
}
}
/**
* 代理类
*
* @author lw
*
*/
public class Proxy implements Subject {
private Subject subject;
public Proxy(Subject subject) {
this.subject = subject;
}
private void method1() {
System.out.println("代理类自己的方法");
}
@Override
public void method() {
// TODO Auto-generated method stub
subject.method();
method1();
}
}
/**
* 测试类
*
* @author lw
*
*/
public class Test {
public static void main(String[] args) {
Player player = new Player();
Proxy proxy = new Proxy(player);
proxy.method();
}
}
11.工厂模式
public class Factories {
public static void main(String[] args) {
serviceConsumer(new Implementation1Factory());
serviceConsumer(new Implementation2Factory());
}
public static void serviceConsumer(ServiceFactory serviceFactory) {
Service service = serviceFactory.getService();
service.method1();
service.method2();
}
}
interface Service {
void method1();
void method2();
}
interface ServiceFactory {
// 返回Service对象
Service getService();
}
class Implementation1 implements Service {
@Override
public void method1() {
System.out.println("Implementation1 method1");
}
@Override
public void method2() {
System.out.println("Implementation1 method2");
}
}
class Implementation1Factory implements ServiceFactory {
@Override
public Service getService() {
return new Implementation1();
}
}
class Implementation2 implements Service {
@Override
public void method1() {
System.out.println("Implementation2 method1");
}
@Override
public void method2() {
System.out.println("Implementation2 method2");
}
}
class Implementation2Factory implements ServiceFactory {
@Override
public Service getService() {
return new Implementation2();
}
}
12.内部类
创建内部类
- 创建内部类的方式就是把类的定义置于外围类的里面。
public class Test01 {
public static void main(String[] args) {
System.out.println(Person.I);
}
class Person {
static final int I = 5;
}
}
使用.this与.new
- 生成对外部类对象的引用,可以使用外部类的名字后面紧跟圆点和this;
public class Test01 {
public static void main(String[] args) {
Test01 test=new Test01();
Test01.Person person= test.new Person();
}
class Person{
}
}
匿名内部类
public class Test01 {
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
super.run();
}
}.start();
}
}
- 内部类最吸引人的原因:
- 每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响;