Java基础

基础整理(一)

1 类和对象

对象

对象是类的一个实例,有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。

类是一个模板,它描述一类对象的行为和状态。

2 基本特征

多态

多态是允许你将父对象设置成为一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public interface Parent //父类接口
{
public void simpleCall();
}
public class Child_A implements Parent
{
public void simpleCall();
{
//具体的实现细节;
}
}
public class Child_B implements Parent
{
public void simpleCall();
{
//具体的实现细节;
}
}

然后,我们就可以看到多态所展示的特性了:

1
Parent pa = new Child_A();

pa.simpleCall()则显然是调用Child_A的方法;

1
Parent pa = new Child_B();

pa.simpleCall()则是在调用Child_B的方法。所以,我们对于抽象的父类或者接口给出了我们的具体实现后,pa 可以完全不用管实现的细节,只访问我们定义的方法,就可以了。

事实上,这就是多态所起的作用,可以实现控制反转。这在大量的J2EE轻量级框架中被用到,比如Spring的依赖注入机制。

继承

继承可以使得子类具有父类的属性和方法或者重新定义、追加属性和方法等。

extends关键字来继承父类。

  1. 子类拥有父类得特征,而父类没有,父类更通用,子类更具体,(特征包括属性和方法,自身的特性,拥有父类没有的)
  2. 使用extends继承父类,语句格式:class 子类名 extends 父类名{}
  3. 父类中一般只定义一般属性和方法(这个一般可以理解为是子类共有的,这就是父类更通用,而子类拥有其他的,所以子类更具体)
  4. 子类中通过super关键字来调用父==构造方法==
  5. 在子类中可以继承父类得那些东西,==哪些不可以继承?==
    父类中publicprotected修饰的属性,方法可以继承,==private修饰的属性和方法不能被继承==
  6. 规则: 创建子类对象的时候,首先调用的是父类的无参构造方法创建一个父类对象
  7. 可以在子类中显示调用父类的有参构造方法
  8. 如果父类的属性均为private修饰,则可以通过共有(public)的gettersetter方法来调用
  9. 可以利用接口来实现与多重继承相似的效果。

关键词:extends

封装

在面向对象程式设计方法中,封装(英语:Encapsulation)是==指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。
==封装可以被认为是一个==保护屏障==,==防止该类的代码和数据被外部类定义的代码随机访问。==
要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。

优点:

  1. 良好的封装能够减少==耦合==。
  2. 类内部的结构可以自由修改。
  3. 可以对成员变量进行更精确的控制。
  4. 隐藏信息,实现细节

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Person{
private String name;
private int age;
public int getAge(){
return age;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public void setName(String name){
this.name = name;
}
}
//采用 this 关键字是为了解决实例变量(private String name)和局部变量(setName(String name)中的name变量)之间发生的同名的冲突。

nameage 属性设置为私有的(private),只能本类才能访问,其他类都访问不了,如此就对信息进行了隐藏如果要访问就要通过公共的方法(public)

关键词:private

3 实例和方法

实例

对象就是类的实例。

创建对象实例的四种方式

  1. 使用new关键字
  2. 利用java的反射机制
  3. 实现Cloneable接口使用克隆方法
  4. 利用java序列化和反序列化实现创建对象
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package com.module;

public class User implements Cloneable{
private String userName;
private int age;
private String addr;
public User(){}
public User(String u,int a,String addr){
this.userName = u;
this.age = a;
this.addr = addr;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
@Override
public String toString() {
return "User [userName=" + userName + ", age=" + age + ", addr=" + addr + "]";
}

public static void main(String[] args) {
//创建对象方式1:使用new关键字
User u1 = new User("1",2,"3");
System.err.println(u1.toString());

//创建对象方式2:使用反射
//发射方式创建对象要求被创建的对象编写空构造
try {
User u2 = User.class.newInstance();
System.err.println(u2.toString());
} catch (InstantiationException | IllegalAccessException e) {
System.out.println("反射创建失败"+e.getMessage());
}
//使用clone方法创建对象:要求被创建或者被克隆的对象实现Cloneable接口
//(3)是在内存上对已有对象的影印,所以不会调用构造函数
try {
User u3 = (User) u1.clone();
System.err.println("u3:"+u3.toString());
System.out.println(u1==u3);//false
} catch (CloneNotSupportedException e) {
System.out.println("克隆创建失败"+e.getMessage());
}
//运用反序列化手段,调用java.io.ObjectInputStream对象的 readObject()方法
//该方法是从文件中还原类的对象,也不会调用构造函数。
}
}

关键词:newclone()

抽象

  1. 抽象类不能被实例化
  2. 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
  3. 抽象类中的抽象方法只是声明,不包含实现过程
  4. 构造方法,类方法(用static修饰的方法)不能声明为抽象方法。
  5. 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。

:问:子抽象类继承父抽象类,必须显性调用父抽象类的显性构造器吗?

并不是说“一定要调用父类的显性构造器”,而是子类在继承父类时,如果父类的显式构造器中有参数,子类要声明给出这个参数。这是一个关于==继承==的问题。

关键词:abstract

方法

定义

1
2
3
4
5
6
7
8
9
修饰符 返回值类型 方法名(参数类型 参数名){
/*修饰符:修饰符,这是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型。
*方法体:方法体包含具体的语句,定义该方法的功能。
*/
...
方法体
...
return 返回值;
}

调用

Java 支持两种调用方法的方式,根据方法是否返回值来选择。

  1. 当程序调用一个方法时,程序的控制权交给了被调用的方法。当被调用方法的返回语句执行或者到达方法体闭括号时候交还控制权给程序。当方法==返回一个值==的时候,方法调用通常被当做一个值。
  2. 如果方法返回值是void,方法调用一定是==一条语句==。

构造方法

当一个对象被创建时候,构造方法用来初始化该对象。构造方法和它所在类的名字相同,但构造方法没有返回值。

当创建对象时,系统会自动调用构造方法

  1. 没有自定义构造方法时,系统会调用默认构造方法
  2. 构造方法可以==重载==,不同的构造方法名字相同,参数列表不同,参数列表是其识别的依据、标志,类似不同人可能有相同的名字,但有不同的身份证号。
  3. 当自定义构造方法时,系统依据传入的==参数类型、数量==,自动匹配构造方法初始化对象

变量作用域

  • 变量的范围是程序中该变量可以被引用的部分。
  • 方法内定义的变量被称为局部变量。
  • 局部变量的作用范围从声明开始,直到包含它的块结束。
  • 局部变量必须声明才可以使用。

重载

  • 一个类的两个方法拥有相同的名字,但是有不同的参数列表。Java编译器会根据方法签名判断哪个方法应该被调用。
  • 方法重载可以让程序更清晰易读。执行密切相关任务的方法应该使用相同的名字。
  • 重载的方法必须拥有不同的参数列表。你不能仅仅依据修饰符或者返回类型的不同来重载方法

重载与覆写

区别 重载(overload) 覆写(override)
概念 方法名称相同,参数的类型和个数不同 方法名称、返回值类型、参数的类型及个数完全相同
范围 一个类 继承关系
限制 没有权限要求 被覆写的方法不能拥有比父类更严格的访问控制权限

重载时最好保持方法返回类型一致

finalize() 方法

Java 允许定义这样的方法,它在对象被垃圾收集器析构(回收)之前调用,这个方法叫做 finalize( ),它用来清除回收对象。

1
2
3
4
protected void finalize()
{
// 在这里终结代码
}//关键字 protected 是一个限定符,它确保 finalize() 方法不会被该类以外的代码调用。

4 static和final

public static void main(String[] args) {}

main为程序入口。

String[] args为命令行参数。

1
2
3
4
5
6
7
public class CommandLine {
public static void main(String args[]){
for(int i=0; i<args.length; i++){
System.out.println("args[" + i + "]: " + args[i]);
}
}
}

在命令行编译:

1
2
3
4
5
6
7
public class CommandLine {
public static void main(String args[]){
for(int i=0; i<args.length; i++){
System.out.println("args[" + i + "]: " + args[i]);
}
}
}

输出:

1
2
3
4
5
6
7
args[0]: this
args[1]: is
args[2]: a
args[3]: command
args[4]: line
args[5]: 200
args[6]: -100

static

“static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。”

==方便在没有创建对象的情况下来进行调用(方法/变量)。==

static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。
static可以用来修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能。

static方法

此时MyObject对象都没有,str2根本就不存在,所以就会产生矛盾了。同样对于方法也是一样,由于你无法预知在print1方法中是否访问了非静态成员变量,所以也==禁止在静态成员方法中访问非静态成员方法==。

而对于非静态成员方法,它访问静态成员方法/变量显然是毫无限制的。

关于构造器是否是static方法可参考:构造器是静态方法吗?

static变量

static变量也称作静态变量,静态变量和非静态变量的区别是:==静态变量被所有的对象所共享,在内存中只有一个副本==,它当且==仅==当在类==初次加载==时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
static成员变量的初始化顺序按照定义的顺序进行初始化。

static代码块

static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,==并且只会执行一次==。

因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。

static关键字的误区

  1. static关键字会改变类中成员的访问权限吗?
    不会

  2. 能通过this访问静态成员变量吗?
    能。静态成员变量虽然独立于对象,但是不代表不可以通过对象去访问,所有的静态方法和静态变量都可以通过对象访问(只要访问权限足够)。

  3. static能作用于局部变量么?
    ==static是不允许用来修饰局部变量。==

这段代码的输出结果是什么?

1
2
3
4
5
6
7
8
9
10
public class Test {   
static{
System.out.println("test static 1");
}
public static void main(String[] args) {
}
static{
System.out.println("test static 2");
}
}

输出:

1
2
test static 1
test static 2

虽然在main方法中没有任何语句,但是还是会输出。

执行main方法之前,必须先加载Test类,而在加载Test类的过程中就会执行static块。

另外,static块可以出现类中的任何地方(==只要不是方法内部,记住,任何方法内部都不行==),并且执行是按照static块的顺序执行的。

final

final 变量
final 方法
final 类
使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?

5 权限修饰符

作用域 当前类 同一package 子孙类 其他package
public
protected ×
friendly × ×
private × × ×

friendly为默认权限。