人机交互方式:
计算机编程语言:
Java语言的特点:
Java注释类型
/**
@author 指定java程序的作者
@version 指定源文件的版本
*/
javadoc -d myjava -author -version JavaComment.java
Java API文档
java程序编写-编译-运行的过程
注意事项
hellojava.java
a. 用于定义数据类型的关键字 |
---|
class |
interface |
enum |
byte |
short |
int |
long |
float |
double |
char |
boolean |
void |
b. 用于定义流程控制的关键字 |
---|
if |
else |
switch |
case |
default |
while |
do |
for |
break |
continue |
return |
c. 用于定义访问权限修饰符的关键字 |
---|
private |
protected |
public |
d. 用于定义类、函数、变量修饰符的关键字 |
---|
abstract |
final |
static |
synchronized |
e. 用于定义类与类之间关系的关键字 |
---|
extends |
implements |
f. 用于定义建立实例以及引用实例、判断实例的关键字 |
---|
new |
this |
super |
instanceof |
g. 用于异常处理的关键字 |
---|
try |
catch |
finally |
throw |
throws |
h. 用于包的关键字 |
---|
package |
import |
i. 其他修饰符关键字 |
---|
native |
strictfp |
transient |
volatile |
assert |
现有java版本尚未使用,但以后可能会作为关键字使用。
定义:java对各种变量、方法和类等要素命名时使用的字符序列。
技巧:凡是自己可以起名字的地方都叫标识符
定义合法标识符规则
Java中名称命名规范
类型 | 说明 | 示例 |
---|---|---|
包名 | 多单词组成时所有字母都小写 | xxxyyy |
类名、接口名 | 多单词组成时,所有单词的首字母大写 | XxxYyyZzz |
变量名、方法名 | 多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写 | xxxYyyZzz |
常量名 | 所有字母都大写,多单词时每个单词用下划线连接 | XXX_YYY_ZZZ |
变量的概念
变量的作用
使用变量的注意事项
整型
类型 | 占用存储空间 | 表数范围 |
---|---|---|
byte | 1字节=8bit位 | -128~127 |
short | 2字节 | [ − 2 15 , 2 15 − 1 ] [-2^{15},2^{15}-1] [−215,215−1] |
int | 4字节 | [ − 2 31 , 2 31 − 1 ] [-2^{31},2^{31}-1] [−231,231−1] |
long | 8字节 | [ − 2 63 , 2 63 − 1 ] [-2^{63},2^{63}-1] [−263,263−1] |
浮点型
类型 | 占用存储空间 | 表数范围 |
---|---|---|
单精度float | 4字节 | |
双精度double | 8字节 |
字符型
注意事项:
布尔型boolean
(byte, short, char) -> int -> long -> float -> double
class VariableTest3{
public static void main(String[] args){
double d1 = 12.9;
//使用强转符
int i1 = (int)d1;//12(截断操作而不是四舍五入)
System.out.println(i1);
}
}
进制 | 说明 |
---|---|
二进制(binary) | 以0b或0B开头 |
十进制(decimal) | |
八进制(octal) | 以数字0开头 |
十六进制(hex) | 以0x或0X开头 |
Java整数常量默认是int型,当用二进制定义整数时,其第32位是符号位;而long型时,二进制默认占64位,第64位是符号位
二进制的整数有如下三种形式:
计算机以二进制补码的形式保存所有整数
decimal | 名称 | bit1(符号位) | bit2 | bit3 | bit4 | bit5 | bit6 | bit7 | bit8 |
---|---|---|---|---|---|---|---|---|---|
14 | 原码/反码/补码 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
-14 | 原码 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
-14 | 反码 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 1 |
-14 | 补码 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 0 |
二进制与十进制互转
二进制与八进制互转
二进制与十六进制互转
运算符 | 说明 | 范例 | 结果 |
---|---|---|---|
+ | 正号 | ||
- | 负号 | ||
+ | |||
- | |||
* | |||
/ | |||
% | 求模 | 7%5 | 2 |
++( ) | 先运算后取值 | a=2;b=++a | a=3;b=3 |
( )++ | 先取值后运算 | a=2;b=a++ | a=3;b=2 |
–( ) | 先运算后取值 | a=2;b=–a | a=1;b=1 |
( )– | 先取值后运算 | a=2;b=a– | a=1;b=2 |
+ | 字符串连接 |
"Hello" instance of String //true
符号 | 说明 |
---|---|
& | 逻辑与 |
&& | 短路与 |
| | 逻辑或 |
|| | 短路或 |
! | 逻辑非 |
^ | 逻辑异或 |
实例
a | b | a&b | a&&b | a|b | a||b | !a | a^b |
---|---|---|---|---|---|---|---|
true | true | true | true | true | false | false | |
true | false | false | false | true | true | false | true |
false | true | false | false | true | true | true | true |
false | false | false | false | false | false | true | false |
注意:开发中推荐使用短路与和短路或
位运算是直接对整数的二进制进行的运算。
运算符 | 运算 | 示例 | 说明 | 细节 |
---|---|---|---|---|
<< | 左移 | 3 << 2 = 12 | 3*2*2=12 | 空缺位补0 |
>> | 右移 | 3 >> 1 = 1 | 3/2=1 | 最高位是0,空缺位补0;最高位是1,空缺位补1 |
>>> | 无符号右移 | 3 >>> 1 = 1 | 3/2=1 | 空缺位补0 |
& | 与运算 | 6 & 3 = 2 | ||
| | 或运算 | 6 | 3 = 7 | |
^ | 异或运算 | 6 ^ 3 = 5 | a ^ b ^ a = b | |
~ | 取反运算 | ~6 = -7 | 各二进制码按补码各位取反 |
class AriTest{
public static void main(String[] args){
int num1 = 10;
int num2 = 20;
System.out.println("num1=" + num1);
System.out.println("num2=" + num2);
//方法一:取值暂存
int temp = num1;
num1 = num2;
num2 = temp;
System.out.println("num1=" + num1);
System.out.println("num2=" + num2);
//方式2:利用位运算的特点(只适用于数值类型)
num1 = num1 ^ num2;
num2 = num1 ^ num2;//num2 <- num1
num1 = num1 ^ num2;//num1 <- num2
System.out.println("num1=" + num1);
System.out.println("num2=" + num2);
}
}
程序从上到下逐行执行,中间没有任何判断和跳转。
根据条件,选择性地执行某段代码。
switch(表达式){
case 常量1:
语句1;
//break;
case 常量2:
语句2;
//break;
......
case 常量N:
语句N;
//break;
default:
语句;
//break
}
说明
根据switch表达式中的值,一次匹配各个case中的常量。一旦匹配成功,则进入相应case执行语句
当调用完当前case执行语句后,则继续不加判断向下执行其他case结构中的执行语句,直至break或结束
要想实现多选一结构,需要在每个case执行语句后面加break关键字
switch中的表达式只能是如下六种类型之一:byte short char int 枚举类型 String
case表达式只能是一个常量,不能是一个范围或boolean
default相当于if-else中的else,default结构也是可选的,而且位置是灵活的
循环语句的四个组成部分
循环的次数
for(1;2;4){
3
}
例题
编写程序从1循环到150,并在每行打印一个值,另外在每个3的倍数行上打印出“foo”,在每个5的倍数行上打印“biz”,在每个7的倍数行上打印“baz”。
class ForExer {
public static void main(String[] args) {
for(int i = 1; i <=150; i++){
System.out.print(i);
if(i % 3 == 0){
System.out.print(" foo");
}
if(i % 5 == 0){
System.out.print(" biz");
}
if(i % 7 ==0){
System.out.print(" baz");
}
System.out.print("\n");
}
}
}
1
while(2){
3;
4;
}
//执行过程:1 --> 2 --> 3 --> 4 --> 2 --> ... --> 2(False)
说明
1.写while循环千万要小心不要丢了迭代条件
2.我们写程序要避免出现死循环
3.for循环和while循环可以相互转换(区别:初始化条件的作用域不一样)
1
do{
3;
4;
}while(2);
//执行过程:1 --> 3 --> 4 --> 2 --> 3 -->...--> 2
说明
1.do-while循环至少会执行一次循环体
2.开发中执行while更多一些,do-while会比较少
class NineNineTest{
public static void main(String[] args){
int m;
for(int i = 1; i <= 9; i++){
for(int j = 1; j <= i; j++){
m = i * j;
System.out.print(i + "*" + j + "=" + m + " ");
}
System.out.println();
}
}
}
class PrimeTest2 {
public static void main(String[] args) {
long start = System.currentTimeMillis();
boolean isFlag;
int primeCount = 0;
for(int i = 2; i <= 100000; i++){
isFlag = true;
for(int j = 2; j * j <= i; j++){
//优化二:取开方数
if(i % j == 0){
isFlag = false;
break;//优化一:只对本身非质数的自然数是有效的
}
}
if(isFlag == true){
// System.out.println(i);
primeCount++;
}
}
long end = System.currentTimeMillis();
System.out.println("质数的个数为:" + primeCount);
System.out.println("所花费的时间为:" + (end - start));//1207
}
}
关键字 | 使用范围 | 循环中的作用 | 相同点 |
---|---|---|---|
break | ① switch-case; ② 循环结构 | 结束当前循环 | 同一作用域内关键字之后不能声明执行语句 |
continue | 循环结构中 | 结束当次循环 | 同一作用域内关键字之后不能声明执行语句 |
数组(Array),是多个相同类型数据按一定顺寻排列的集合,并使用一个名字命名,通过编号的方式对这些数据进行统一管理。
总结:数组一旦初始化完成,其长度就确定了
调用数组的指定位置的元素
获取数组长度
遍历数组
数据类型 | 初始化值 |
---|---|
整型(byte short int long) | 0 |
浮点型(double float) | 0.0 |
char型 | 0 (ascii码0)或’\u0000’ |
boolean型 | false |
引用数据类型 | null |
内存的简化结构:
一维数组的内存解析:
class test {
public static void main(String[] args){
int[] arr = new it[]{
1,2,3};
//左边arr放入栈中;右边数组放入堆中
//Stack:
// arr: 0x34ab
//heap:
//0x34ab:| 1 | 2 | 3 |
String[] arr1 = new String[4];
//Stack:
// arr1: 0x12ab
//heap:
//0x12ab:| null | null | null | null |
arr1[1]="刘德华";
//Stack:
// arr1: 指向地址
//heap
// 第二个元素修改为刘德华
//0x12ab:| null | 刘德华 | null | null |
arr1 = new String[3];
//Stack:
// arr1: 覆盖原地址
// arr1: 0x5566
//heap
// 0x5566: | null | null | null |
}
}
二维数组可以看成是一维数组array1作为另一个一维数组array2的元素而存在。
其实,从数组底层的运行机制来看,没有多维数组。
调用数组指定位置的元素
获取数组长度
遍历数组
class test {
public static void main(String[] args){
int[][] arr1 = new int[4][];
//Stack:
// arr1: 0x1234
//heap:
// 0x1234: | null | null | null | null |
arr1[1] = new int[]{
1,2,3};
//Stack:
// arr1: 0x1234
//heap:
// 0x1234: | null | 0x7788 | null | null |
// 0x7788: | 1 | 2 | 3 |
arr1[2] = new int[4];
//Stack:
// arr1: 0x1234
//heap:
// 0x1234: | null | 0x7788 | 0x8374 | null |
// 0x7788: | 1 | 2 | 3 |
// 0x8374: | 0 | 0 | 0 |
arr1[2][1] = 30;
//Stack:
// arr1: 0x1234
//heap:
// 0x1234: | null | 0x7788 | 0x8374 | null |
// 0x7788: | 1 | 2 | 3 |
// 0x8374: | 0 | 30 | 0 |
}
}
算法的五大特征
通常来说,排序的目的是快速查找。
public class BubbleSortTest {
public static void main(String[] args) {
int[] arr = new int[10];
for(int i = 0; i < arr.length; i++) {
arr[i] = (int)(Math.random() * 100);
System.out.print(arr[i] + "\t");
}
//冒泡排序
for(int i = 0; i < arr.length - 1; i++) {
int count = 0;
for(int j = 0; j < arr.length - i - 1; j++) {
if(arr[j] > arr[j + 1]){
arr[j] = arr[j] ^ arr[j + 1];
arr[j + 1] = arr[j] ^ arr[j + 1];
arr[j] = arr[j] ^ arr[j + 1];
count++;
}
}
if(count++ == 0){
break;
}
}
System.out.println("\n排序后的数组为:");
for(int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + "\t");
}
}
}
快速排序(Quick Sort)由图灵奖获得者Tony Hoare发明,被列为20世纪十大算法之一,是迄今为止所有内排算法中速度最快的一种。它是冒泡排序的升级版,交换排序的一种。快速排序的时间复杂度为 O ( n log n ) O(n\log{n}) O(nlogn)。
快速排序通常明显比同为 O ( n log n ) O(n\log{n}) O(nlogn)的其他算法更快,因此经常被采用。
快排采用了分治法的思想,所以再很多笔试面试中能经常看到快排的影子。
/**
* 随机生成基准值的基本快速排序
*/
import java.util.Scanner;
import java.util.Arrays;
public class QuickSort {
public static void main(String[] args) {
//单数组排序
Scanner scan = new Scanner(System.in);
System.out.print("请输入随机数组下限(整数):");
int ll = scan.nextInt();
System.out.print("请输入随机数组上限(整数):");
int ul = scan.nextInt();
System.out.print("请输入随机数组长度(整数):");
int n = scan.nextInt();
int[] arr = new int[n];
for(int i = 0; i < arr.length; i++) {
arr[i] = (int)(Math.random() * (ul - ll + 1) + ll);
}
System.out.println("排序前的随机数组为:\n" + Arrays.toString(arr));
QuickSort(arr);
System.out.println("排序后的随机数组为:\n" + Arrays.toString(arr));
//排序测试
}
public static void QuickSort(int[] arr) {
//调用QuickSort(arr, low, high)
QuickSort(arr, 0, arr.length - 1);
}
public static void QuickSort(int[] arr, int low, int high) {
//先分区,后递归排序
if (low < high) {
int p = partition(arr, low, high);
QuickSort(arr, low, p - 1);
QuickSort(arr, p + 1, high);
}
}
public static int partition(int[] arr, int low, int high) {
//分区并返回基准值位置
//定义指针
int i = low;
int j = high;
//随机生成基准值
int p = (int)(Math.random() * (high - low + 1) + low);
//取中间值作为基本值
// int p = (int)((high + low) / 2);
//分区操作
while (i < j) {
//从左往右找到大于等于基准值的数字
while (i < j && arr[i] < arr[p]) {
i++;
}
//从右往左找到小于等于基准值的数字
while (i < j && arr[p] < arr[j]) {
j--;
}
if(i < j) {
arr[i] = arr[i] ^ arr[j];
arr[j] = arr[i] ^ arr[j];
arr[i] = arr[i] ^ arr[j];
if(i == p) {
p = j;
i++;
}else if(j == p) {
p = i;
j--;
}else {
i++;
j--;
}
}
}
return p;
}
}
java.util.Arrays类即为操作数组的工具类,包含了用来操作数组(比如排序和搜索)的各种方法。
no. | expression | description |
---|---|---|
1 | boolean equals(int[] a, int[] b) | 判断两个数组是否相等 |
2 | String toString(int[] a) | 输出数组信息 |
3 | void fill(int[] a, int val) | 将指定值填充到数组之中 |
4 | void sort(int[] a) | 对数组进行排序 |
5 | int binarySearch(int[] a, int key) | 对排序后的数组进行二分法检索指定的值 |
面向对象:Object Oriented Programming
面向过程:Procedure Oriented Programming
类(Class)和对象(Object)是面向对象的核心概念。
面向对象程序设计的重点是类的设计。设计类,就是设计类的成员。
属性(成员变量) vs 局部变量
定义:方法描述了类应该具有的功能。
public void eat(){
} //没有返回值,没有形参
public void sleep(int hour){
} //没有返回值,带形参
public String getName(){
} //返回值为字符串类型,不带形参
public String getNation(String nation){
} //返回值为字符串类型,带形参
权限修饰符 返回值类型 方法名(形参列表{方法体}
说明:
JavaSE 5.0中提供了Varargs(variable number of arguments)机制,允许直接定义能和多个实参相匹配的形参。
从而可以用一种更简单的方法来传递个数可变的形参。
定义:一个方法体内调用它自身。
定义:在子类中可以根据需要对父类中继承来的方法进行改造,也成为方法的重置、覆盖。
声明:
权限修饰符 返回值类型 方法名(形参列表) throws 异常的类型 {
}
要求:
注意:子类与父类中同名同参数的方法必须同时声明为非static的(即为重写),或者同时声明为static的(不是重写)
因为static方法是属于类的,子类无法覆盖父类的方法。
权限修饰符protected
不同package下的子类可以调用其父类protected的结构,不能调用private/(缺省)的结构。
权限修饰符 类名(形参列表) { }
以上操作的先后顺序:1 -> 2
JavaBean是一种Java语言写成的可重用组件。
所谓JavaBean,是指符合如下标准的Java类:
用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以用Java代码创造的对象进行打包,
并且其他的开发者可以通过内部的JSP页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。
用户可以认为JavaBean提供了一种随时随地的复制和粘贴功能,而不用关心任何改变。
内部类的分类:成员内部类(静态、非静态) VS 局部内部类(方法内、代码块内、构造器内)
class Outer {
public String name;
public int count;
public void show() {
System.out.println("Class: Outer");
}
//成员内部类(静态)
static class Dog {
String name;
int age;
public void bark() {
System.out.println("喵喵喵");
// show();静态结构先加载,不能调用非静态方法
}
}
//成员内部类(非静态)
class Bird {
String name;
public Bird() {
}
{
show();
Outer.this.show();
}
public void sing() {
System.out.println("我是一只小小鸟");
}
public void display(String name) {
System.out.println(name);//方法的形参
System.out.println(this.name);//内部类的属性(ps就近原则)
System.out.println(Outer.this.name);//外部类的属性
}
}
}
开发中常见的内部类:
public class InnerClassTest {
//开发中少见的形式
public void method() {
//局部内部类
class AA {
}
}
//返回一个实现了Comparable接口的类的对象
public Comparable getComparable() {
//创建一个实现了Comparable接口的类:局部内部类
//方式1:非匿名形式
class MyCompare implements Comparable {
@Override
public int compareTo(Object o) {
return 0;
}
}
return new MyCompare();
//
//方式2:匿名形式的实现类
// return new Comparable() {
// @Override
// public int compareTo(Object o) {
// return 0;
// }
// };
}
}
public class InnerClassTest {
public static void main(String[] args) {
//创建Dog实例(静态的成员内部类):
Outer.Dog dog = new Outer.Dog();
dog.bark();
//创建Bird实例(非静态的成员内部类):
Outer o = new Outer();
Outer.Bird bird = o.new Bird();
bird.sing();
Outer.Bird bird2 = o.new Bird();
bird2.sing();
}
}
当我们创建一个类的对象以后,我们可以通过“对象.属性”的方式,对其属性进行赋值。
这里赋值操作要受到属性的数据类型和存储范围的制约,除此之外,没有其他制约条件。
但是,在实际问题中,我们往往需要给属性赋值加入额外的限制条件(如private),使其只能通过方法进行有限制的访问。
–>此时,针对属性就体现了封装性。
我们将类的属性私有化(private),同时,提供public方法来获取(getXxx)和设置(setXxx)此属性的值。
拓展:封装性的体现举例
封装性的体现,需要权限修饰符来配合
修饰符 | 类内部 | 同一个包 | 不同包的子类 | 同一个工程 |
---|---|---|---|---|
private | Yes | |||
(缺省) | Yes | Yes | ||
protected | Yes | Yes | Yes | |
public | Yes | Yes | Yes | Yes |
总结:Java提供了4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用是的可见性的大小。
Why Inheritance?
格式
基本格式:class A extends B{}
体现:一旦子类A继承父类B之后,子类A中就获取了父类B中声明的属性和方法
Java只支持单继承和多层继承,不允许多重继承
Object是所有Java类的根父类。如果我们没有显式地声明一个类地父类的话,则此类继承于java.lang.Object类。
所有的Java类都直接或间接地继承于java.lang.Object类,都继承了它的结构和功能。
Constructor(s)
Object()
Methods
Modifier | Type | Method | Description |
---|---|---|---|
protected | Object | clone() | 复制一个对象 |
boolean | equals(Object obj) | ||
protected | void | finalize() | 当栈空间没有变量指向堆空间的对象时,将调用此方法回收堆空间中的对象 |
Class> | getClass() | 返回直接父类 | |
int | hashCode() | Returns a hash code value for the object | |
String | toString() |
public boolean equals(Object obj) { return (this == obj); }
class GeometricObject {
protected String color;
protected double weight;
protected GeometricObject() {
}
protected GeometricObject(String color, double weight) {
this.color = color;
this.weight = weight;
}
public double getWeight() {
return weight;
}
public String getColor() {
return color;
}
public void setWeight(double weight) {
this.weight = weight;
}
public void setColor(String color) {
this.color = color;
}
public double findArea(){
return 0.00;
}
//自定义equals方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GeometricObject that = (GeometricObject) o;
return Double.compare(that.weight, weight) == 0 &&
Objects.equals(color, that.color);
}
@Override
public int hashCode() {
return Objects.hash(color, weight);
}
}
public String toString() {return getClass().getName() + “@” + Integer.toHexString(hashCode())}
包装类是Java针对8种基本数据类型定义的相应的引用类型。它使基本数据类型有了类的特点,
因而可以直接调用类中的方法,这时Java才是真正地面向对象。
基本数据类型 | Wrapper | 父类 |
---|---|---|
byte | Byte | Number |
short | Short | Number |
int | Integer | Number |
long | Long | Number |
float | Float | Number |
double | Double | Number |
boolean | Boolean | |
char | Character |
需要明确的是,虽然创建子类对象时调用了父类的构造器,但至始至终就创建了一个对象,即为new的子类对象。
//向下转型使用细节的举例
public class PolymorphismTest {
public static void main(String[] args){
//问题1: 编译通过,运行时不通过
//举例1:
Person p1 = new Woman();
Man m1 = (Man)p1;
//举例2:
Person p2 = new Person();
Man m2 = (Man)p2;
//问题2:编译通过,运行也通过
Object obj = new Woman();
Person p3 = (Person)obj;
//问题3:编译不通过
//类型不匹配
Man m3 = new Woman();
}
}
class Person {
}
class Man extends Person {
}
class Woman extends Person {
}
面试题:谈谈对多态的理解
从编译和运行的角度看:
this表示当前对象(或当前正在创造的对象,构造器中),可以调用类的属性、方法和构造器
public class Person {
private String name;
//空参构造器
public Person() {
//Person初始化的40行代码
}
//带参数的构造器
public Person(String name) {
this();//执行空参构造器中的40行代码
this.name = name;
}
}
如this可理解为“自己的”一样,super可理解为“父类的”。
super可用来调用父类的属性、方法、构造器
我们可以在子类的方法或构造器中,通过使用super.属性或super.方法,显式地调用父类中声明地属性或方法,但是通常情况下我们习惯省略super。
我们可以在子类的构造器中显式地使用super(形参列表)的方式,调用父类中声明的指定的构造器。
当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过new关键字才会产生出对象,这时系统才会
分配内存空间给对象,其方法才可以供外部调用。
我们有时候希望无论是否产生了对象或者无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份。
static可以用来修饰:属性、方法、代码块、内部类(不能修饰构造器)
static修饰属性: 静态变量
static修饰方法
static注意点:
Q: 实际开发中,如何确定一个结构要不要声明为static?(类变量 or 实例变量?)
final: 可以用来修饰类、方法、变量
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般、更通用。类的设计应该保证父类和子类能够共享特征。
有时,将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
abstract可以用来修饰的结构:类、方法
public class PersonTest {
public static void main(String[] args) {
method(new Student());//匿名对象
Worker worker = new Worker();
method1(worker);//非匿名的类,非匿名的对象
method1(new Worker());//非匿名的类的匿名对象
//创建了一个匿名子类的对象:p
Person p = new Person() {
public void breathe() {
System.out.println("吃东西");
};
public void speak(String lang) {
System.out.println("好好呼吸");
};
};
method1(p);
//创建匿名子类的匿名对象
method1(new Person() {
@Override
public void speak(String lang) {
System.out.println("匿名子类的匿名对象在说话");
}
@Override
public void breathe() {
System.out.println("匿名子类的匿名对象在呼吸");
}
});
}
public static void method1(Person p) {
p.breathe();
p.speak("Human Language");
}
public static void method(Student s) {
}
}
在编程过程中,有两个方面的需求需要用接口来实现。
一方面,Java不支持多重继承,但有时必须从几个类中派生出一个子类,继承它们所有的属性和方法;
另一方面,有时必须从几个类中抽取出一些共同的行为特征,而它们之间没有is-a的关系,仅仅是具有相同的行为特征而已。
例如:鼠标、键盘、打印机、手机、数码相机等都支持USB连接。
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要…则必须能…”的思想。
继承是一个“是不是”的关系,而接口实现则是“能不能”的关系。
接口的具体使用,体现了多态性。
接口使用interface关键字来定义:
class AA extends BB implements CC,DD,EE {
}
如何定义接口:定义接口中的成员
接口使用的注意事项
接口的实现
Java开发中,接口通过类去**实现(Implements)**的方式来使用
* 如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化;否则只能作为一个抽象类
* Java类可以实现多个接口 --> 弥补了Java单继承性的局限性
* 接口与接口之间可以继承,且可以多继承
Java8中,你可以为接口添加静态方法和默认方法。从技术角度来说,这是完全合法的,只是它看起来违反了接口作为一个
抽象定义的理念。
为了更好地实现项目中类的管理,提供了包的概念。
位置:源文件首行
结构:"."代表文件目录的结构
注意事项:
我们可以在源文件中显式地使用import结构导入指定包下的类、接口。import声明在package和class之间。
编译完源程序之后,生成一个或多个字节码文件。
我们使用JVM中的类的加载器和解释器堆生成的字节码文件进行解释运行。这意味着需要将字节码文件对应的类加载到内存中,涉及到内存解析。
《JVM规范》
设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。
MVC是常用的设计模式之一,将整个程序分为三个层次:视图模型层、控制器层、数据模型层。
这种将程序输入输出、数据处理,以及数据的展示分离开来的设计模式使程序结构变得灵活而且清晰,同时也描述了程序各个对象间的通信方式,
降低了程序的耦合性。
作用:处理数据
作用:显示数据
作用:处理业务逻辑
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得
其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器访问权限设置为private,这样
就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。由于在类的外部一开始无法得到类的对象,只能
调用该类的某个静态方法以返回内部创建的对象。静态方法也只能访问类中的静态成员变量,所以,只想类内部产生的该对象的变量
也必须定义为静态的。
饿汉式和懒汉式的区别:
由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,
如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单丽对象,然后
永久驻留内存的方式来解决。
例: java.lang.Runtime
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,
但子类总体上会保留抽象类的行为方式。
解决的问题:
代理模式是Java开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问。
public class NetworkTest {
public static void main(String[] args) {
Server s = new Server();
ProxyServer ps = new ProxyServer(s);
ps.browse();
}
}
interface Network {
public void browse();
}
class Server implements Network {
@Override
public void browse() {
System.out.println("真实的服务器访问网络");
}
}
class ProxyServer implements Network {
private Network network;
public ProxyServer(Network network) {
this.network = network;
}
public void check() {
System.out.println("联网之前的检查工作");
}
@Override
public void browse() {
check();
network.browse();
}
}
实现了创建者与调用者的分离,即将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。
常用的调试的方法:
main()方法的使用说明:
在使用计算机语言进行项目开发的过程中,即使程序员把代码写得尽善尽美,在系统的运行过程中仍然会
遇到一些问题,因为很多问题不是靠代码能够避免的,比如:客户输入数据的格式,读取文件是否存在,
网络是否始终保持通畅等等。
Java程序在执行过程中所发生的异常事件可分为两类:
Step1:抛
Step2:抓(可以理解为异常的处理方式)
class Test() {
public void method() {
try {
//可能出现异常的代码
} catch (异常类型1 变量名1){
//处理异常的方式1
}catch(异常类型2 变量名2){
//处理异常的方式2
}
finally{
//一定会执行的代码
}
}
}
注意事项:
其他细节:
关键字 | 捕获异常 | 抛出异常 | 声明异常 |
---|---|---|---|
try | 执行可能产生异常的代码 | x | x |
catch | 捕获异常 | x | x |
finally | 无论是否发生异常,代码总被执行 | x | x |
throw | x | 异常的生成阶段:手动抛出异常类对象 | x |
throws | x | x | 声明方法可能要抛出的异常类 |