JavaBaseNote

[TOC]

对象

  • 万物皆对象

按照通俗的说法,每个对象都是某个类(class)的一个实例(instance),这里,‘类’就是‘类型’的同义词。
——《JAVA编程思想》

简而言之,对象是类的实例。比如所有的电脑叫“电脑”,电脑是一个类,而具体下来,你的mac是一个对象,是“电脑”的实例。

对象引用

举例:

1
Person person = new Person("大大卷");
  1. 在堆空间里创建一个Person类对象
  2. 末尾的()意味着在对象创建后,立即调用Person类的构造函数,对刚生成的对象进行初始化。
  3. 等号左边,其实是创建了一个Person类引用变量person,用来指向Person对象的对象引用。
  4. “=”操作符使对象引用指向刚创建的Person对象
1
2
Person person;
person = new Person("大大卷");

两段代码功能一样。

两个实体:对象引用变量和对象本身。

一个Person类可以创建出无数个对象,但这些对象不可能全不都叫“Peron”叭 _(:з」∠) _

对象连名都没有,没法直接访问它。我们只能通过对象引用来间接访问对象。

Java中都是通过引用来操纵对象的。

Java对象和引用的关系可以说是互相关联,却又彼此独立。彼此独立主要表现在:引用是可以改变的,它可以指向别的对象。

从存储空间上来说,对象和引用也是独立的,它们存储在不同的地方,对象一般存储在堆中,而引用存储在速度更快的堆栈中。

对象好比是一只很大的气球,引用变量则是一根可以用来系气球的绳子。

如果只执行了第一条语句,还没执行第二条,此时创建的引用变量person还没指向任何一个对象,它的值是null。

引用变量可以指向某个对象,或者为null。

它是一根绳,一根还没有系上任何一个汽球的绳。执行了第二句后,一只新汽球做出来了,并被系在person这根绳上。抓住这根绳,就等于抓住了那只汽球。

每种编程语言都有自己的数据处理方式。有些时候,程序员必须注意将要处理的数据是什么类型。你是直接操纵元素,还是用某种基于特殊语法的间接表示(例如C/C++里的指针)来操作对象。所有这些在 Java 里都得到了简化,一切都被视为对象。因此,我们可采用一种统一的语法。尽管将一切都“看作”对象,但操纵的标识符实际是指向一个对象的“引用”(reference)

也就是说person是一个引用,是指向一个可以指向Person类的对象的引用。真正创建对象的语句是右边的new Person(“大大卷”);

事实上到这里还会有点懵,但再看下面的例子就会比较清晰了:

1
2
3
Person person;
person = new Person("大大卷");
person = new Person("毛毛虫");

先让person指向了大大卷这个对象,然后又指向了毛毛虫这个对象。da ga la!!Person person只是生命了一个Person类的引用,它可以指向任何Person类的实例。类似于:

1
2
3
int a;
a=2;
a=3;

哇塞这个就很清楚啦=-=先声明一个int类型的变量a,对a赋值为2,然后又赋值为3.

如果来一句

1
2
Person person2;
person2 = person

其实发生的是复制行为。但是对象本身没有被复制,被复制的知识对象引用。person2也指向了person所指向的对象。两根绳系的是同一只气球哦!!!

然后,如果

1
2
person2 = new Person();
person = person2;

那么person也指向了第二个对象,而第一个对象呢?飞走啦,据说是被JAVA的垃圾回收机制回收了,emmmmmm好吧 这很可以

and如果仅仅是为了打印而生成一个对象,就不需要用引用变量来系住它。例如打印字符串:

1
System.out.println(“I”);

字符串对象“I”在打印后即被丢弃。有人把这种对象称之为临时对象。

对象与引用的关系将持续到对象回收。

完了对象回收又是咋回事啊/笑哭

总之,
在初始化时,“=”语句左边的是引用,右边new出来的是对象。在后面的左右都是引用的“=”语句时,左右的引用同时指向了右边引用所指向的对象

参考:

为什么要接口

抽象类:每个类只能扩展于一个类,不能扩展第二个类了

but每个类可以实现多个接口

避免多重继承的复杂性和低效性。

break||continue||return

break 用于完全结束一个循环,跳出循环体。不管哪种循环,一旦在循环体中遇到break,系统将完全结束掉该循环。

continue只是忽略本次循环剩下的语句,立即开始下次循环,并不会终止循环;而break则是完全终止循环。

return不是专门拿来结束循环的,return的功能是结束一个 方法 。当一个方法执行到一个return语句时,这个方法将会给结束。

方法

封装了由一系列语句所描述的运算

need 参数(parameter) 算出某种数据类型的返回值

性质

  1. 方法的参数按值传递

不能改变原数组变量本身

  1. 方法名可以被重载
  2. 方法只能返回一个值
    but可以有多个return语句
  3. 方法可以产生副作用

void 类型的静态方法会产生副作用(接受输入、产生输出、修改数组或者改变系统状态)

静态方法&非静态方法(实例方法)

又称函数——一组在被调用时会被顺序执行的语句.

made of 签名(关键字public static以及函数的返回值,方法名以及一串各种类型的参数)和函数体(即{code})

我终于在今天(24号,晚到惭愧)体会到 这其实跟数学里的函数意思是差不多的,就像一个计算过程一样

调用函数只需要:方法名(参数)

封装

对于封装而言,一个对象它所封装的是自己的属性和方法,所以它是不需要依赖其他对象就可以完成自己的操作。

1
2
3
4
5
6
7
8
9
使用封装有三大好处:

1、良好的封装能够减少耦合。

2、类内部的结构可以自由修改。

3、可以对成员进行更精确的控制。

4、隐藏信息,实现细节。

继承

构造器

  • 子类可以继承父类的属性和方法,但不能继承构造器,只能调用父类的构造器

使用super()

protected关键字

向上转型

多态

一个对象变量可以指示多种实际类型的现象被称为多态

在运行时能够自动地选择调用哪个方法的现象称为动态绑定

反射

指能够分析类能力的程序。
反射库大量应用于JavaBeans中

  1. 在运行时分析类的能力

检查类的结构

  1. 在运行时查看对象
  2. 实现通用的数组操纵代码
  3. 利用method对象(类比于c++函数指针

try{可能抛出已检查异常的方法调用代码}

catch{处理器代码}

接口

接口不是类,而是对类的一组需求描述(可以看成是没有实例域的抽象类

1)将类声明为实现给定的接口
2)对接口中所有方法进行定义

要将类声明为实现某个接口,需要使用implements

1.所有方法自动属于public;接口中的域将被自动设为public static final

2.接口不是类,尤其不能用new运算符实例化一个接口;

1
x = new Comparable() // ERROR

尽管不能构造接口的对象,却能声明接口的变量

1
Comparable x; // Ok

接口变量必须引用实现了接口的类对象;

1
x = new Employee() // ok provide Employee implements Comparable

接口可以被拓展

1
2
3
4
5
6
7
8
public interface Moveable
{
void move(double x, double y);
}
public interface Powered extends Moveable
{
double milesPerGallon();
}

虽然在接口中不能包含实例域或静态方法,但却可以包含常量

回调是一种常见的程序设计模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.company;


import javax.swing.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.Timer;
import java.awt.event.ActionListener;


public class TimerTest {

public static void main(String[] args) {
ActionListener listener = new TimePrinter();
Timer t = new Timer(1000, listener);
t.start();

JOptionPane.showMessageDialog(null, "Quit program?");
System.exit(0);

}
}

class TimePrinter implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
System.out.println("At the tone, the time is "+ new Date());
Toolkit.getDefaultToolkit().beep();
}
}

lambda表达式

Java是一种面向对象语言,所以必须构造一个对象,这个对象的类需要有一个方法能包含所需的代码

lambda表达式就是一个代码块,以及必须传入代码的变量规范

即使lambda表达式没有参数,仍然要提供空括号,就像无参数方法一样

1
() -> { for (int i = 100; i>=0; i--) System.out.println(i);}

lambda表达式:

  • 一个代码块
  • 参数
  • 自有变量的值 指非参数而且不在代码中定义的变量
  • (闭包)

对于只有一个抽象方法的接口,需要这种接口的对象时,就可以提供一个lambda表达式。这种接口称为函数式接口(必须有一个抽象方法)

最好把lambda表达式看做是一个函数,而不是一个对象,接受lambda表达式可以传递到函数式接口

lambda表达式转换接口:

1
2
3
4
5
6
Timer t = new Timer(1000, event ->
{
System.out.println("At the tone, the time is "+ new Date());
Toolkit.getfaultToolkit().beep();

})

方法引用
(现有的方法可以完成想要传递到其他代码的某个动作)

1
Timer t = new Timer(1000, event -> System.out.println(event));

等于

1
Timer t = new Timer(1000,System.out::println);

方法引用:

1
System.out::println

等价于lambda表达式

1
x -> System.out.println(x)

要用::操作符分隔方法名与对象或类名

  • object::instanceMethod
  • Class::staticMethod

方法引用等价于提供方法参数的lambda表达式

  • Class::instanceMethod

第一个参数会成为方法的目标

类似于lambda表达式,方法引用不能独立存在,总是会转换为函数式接口的实例。

构造器引用

1
2
3
ArrayList<String> names = ...;
Stream<Person> stream = names.stream().map(Person::new);
List<Person> people = stream.collect(Collectors.toList());

变量作用域

lambda表达式可以捕获外围作用域中变量的值,但能引用值不会改变的变量

在一个lambda表达式中使用this关键字时,是指创建这个lambda表达式的方法的this参数

1
2
3
4
5
6
7
8
9
10
public class Application()
{
public void init()
{
ActionListener listener = event ->
{
System.out.println(this.toString());
}
}
}

处理

延迟执行

  • 在一个单独的线程中运行代码
  • 多次运行代码
  • 在算法的适当位置(例如,排序中的比较操作
  • 发生某种情况
  • 必要时

内部类

定义在另一个类中的类

why we need:

  • 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据
  • 内部类可以对同一个包中的其他类隐藏起来
  • 想要定义一个回调函数:匿名内部类

内部类

  • 所有静态域都必须是final

因为我们希望一个静态域只有一个实例,不过对于每个外部对象,会分别有一个单独的内部类实例。如果这个域不是final,他可能就不是唯一的。

  • 不能有static方法

使用内部类访问对象状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class TalkingClock
{
private int interval;
private boolean beep;

public TalkingClock(int interval, boolean beep)
{
this.interval = interval;
this.beep = beep;
}

public void start()
{
ActionListener listener = new TimePrinter();
Timer t = new Timer(interval, listener);
t.start();
}

public class TimePrinter implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
System.out.println("At the tone, the time is "+ new Date());
if(beep) Toolkit.getDefaultToolkit().beep();
}
}
}

TimePrinter类位于TalkingClock类内部,这并不意味着每个TalkingClock都有一个TimePrinter实例域,TimePrinter对象是由TalkingClock类的方法构造

TimePrinter类没有实例域或者名为beep的变量,beep引用了创建TimePrinter的TalkingClock对象的域

一个方法可以引用调用这个方法的对象数据域,内部类既可以访问自身的数据域,也可以访问创建他的外围对象的数据域

内部类的对象总有一个隐式引用,它指向了创建他的外部类对象,这种引用是不可见的!!

局部内部类

1
2
3
4
5
6
7
8
9
10
11
public void start()
{
class TimePrinter implements ActionListener
{
public void actionPerformed(Action event)
{
System.out.println("At the tone, the time is " + new Date());
if(beep) Toolkit.getDefaultToolkit().beep();
}
}
}
  • 不能用public/private声明

作用域被限定在声明这个局部类的块中,对外部世界完全隐藏
即使TalkingClock类中的其他代码也不能访问它,除start方法外,没有任何方法知道TimePrinter类的存在了哦!!!

  • 不仅能够访问包含它们的外部类,还可以访问局部变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void start(int interval, boolean beep)
{
class TimePrinter implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
System.out.println("At the tone, the time is "+ new Date());
if(beep) Toolkit.getDefaultToolkit().beep();
}
}

ActionListener listener = new TimePrinter();
Timer t = new Timer(interval, listener);
t.start();
}

匿名内部类
假如只创建这个类的一个对象,就不必命名了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void start(int interval, boolean beep)
{
ActionListener listener = new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
System.out.println("At the tone, the time is "+ new Date());
if(beep) Toolkit.getDefaultToolkit().beep();
}
};

Timer t = new Timer(interval, listener);
t.start();
}

————创建一个实现ActionListener接口的类的新对象,需要实现的方法actionPerformed定义在{}内

1
2
3
4
new SuperType(construction parameters)
{
inner class methods and data
}

SuperType可以是接口(ActionListener),内部类需要实现这个接口;

SuperType可以是一个类,内部类就要扩展他

由于构造器名字必须与类名相同,而匿名类没有类名,所以匿名类无构造器。只有将构造器参数传递给超类构造器。

内部类实现接口的时候,不能有任何构造参数!!!

1
2
3
4
new InterfaceType()
{
method and data
}

如果构造参数的闭小括号后面跟一个开大括号,正在定义的就是匿名内部类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package annoymousInnerClass;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;

public class AnonymousInnerClassTest
{
public static void main(String[] args)
{
TalkingClock clock = new TalkingClock();
clock.start(1000,true);

JOptionPane.showMessageDialog(null, "quit program?");
System.exit(0);
}
}

class TalkingClock
{
public void start(int interval, boolean beep)
{
ActionListener listener = new ActionListener()
{
public void actionPerformed(ActionEvent event) {
System.out.println("At the tone, the time is " + new Date());
if(beep) Toolkit.getDefaultToolkit().beep();
}
};
Timer t = new Timer(interval, listener);
t.start();
}
}

静态内部类
对象中不需要引用任何其他的对象,不需要访问外围类对象的时候 为此可以将这个内部类声明为static

只有内部类能够声明为static。静态内部类的对象除了没有对生成它的外围类对象的引用特权外,与其他所有内部类完全一样。

可以有静态域和方法

代理

利用代理可以在运行时创建一个实现了一组给定接口的新类