【JAVA学习笔记1】 面向对象基础

JAVA知识点多,写点笔记,整理3.25 周一上午JAVA课内容,

方法

private字段

当字段被修饰为private时,外部代码无法访问该字段。我们可以用调用类里的方法间接访问该字段,确保了封装性和安全性

private方法

private字段一样,private方法也不允许类外的代码调用。

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
public class Main {
public static void main(String[] args) {
Person ming = new Person();
ming.setBirth(2008);
System.out.println(ming.getAge());
}
}

class Person {
private String name;
private int birth;

public void setBirth(int birth) {
this.birth = birth;
}

public int getAge() {
return calcAge(2019); // 调用private方法
}

// private方法:
private int calcAge(int currentYear) {
return currentYear - this.birth;
}
}

观察上述代码,calcAge()是一个private方法,外部代码无法调用,但是,内部方法getAge()可以调用它。此外,我们还注意到,这个Person类只定义了birth字段,没有定义age字段,获取age时,通过方法getAge()返回的是一个实时计算的值,并非存储在某个字段的值。这说明方法可以封装一个类的对外接口,调用方不需要知道也不关心Person实例在内部到底有没有age字段。

可变参数(E)

可变参数用类型…定义,可变参数相当于数组类型:

1
2
3
4
5
6
7
class Animal{
private String[] names;

public void setNames(String... names) {
this.names = names;
}
}

上面的setNames()就定义了一个可变参数。调用时,可以这么写:
1
2
3
4
5
Animal g = new Animal();
g.setNames("cat", "dog", "cow"); // 传入3个String
g.setNames("cat", "dog"); // 传入2个String
g.setNames("cat"); // 传入1个String
g.setNames(); // 传入0个String

完全可以把可变参数改写为String[]类型:

1
2
3
4
5
6
7
class Animal {
private String[] names;

public void setNames(String[] names) {
this.names = names;
}
}

但是,调用方需要自己先构造String[],比较麻烦。例如:

1
2
Animal g = new Animal();
g.setNames(new String[] {"cat", "dog", "cow"}); // 传入1个String[]

另一个问题是,调用方可以传入null

1
2
Animal g = new Animal();
g.setNames(null);

而可变参数可以保证无法传入null,因为传入0个参数时,接收到的实际值是一个空数组而不是null。

可变参数感觉跟重载异曲同工嘛,都由参数形式决定方法的结果。

参数绑定(E)

调用方把参数传递给实例方法时,调用时传递的值会按参数位置一一绑定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//基本类型参数绑定
public class Main {
public static void main(String[] args) {
Person p = new Person();
int n = 15; // n的值为15
p.setAge(n); // 传入n的值
System.out.println(p.getAge()); // 15
n = 20; // n的值改为20
System.out.println(p.getAge()); // 15还是20?
}
}

class Person {
private int age;

public int getAge() {
return this.age;
}

public void setAge(int age) {
this.age = age;
}
}

此时np.age两者互不影响,setAge()方法复制了n的值

重点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//引用类型参数绑定
public class Main {
public static void main(String[] args) {
Person p = new Person();
String[] fullname = new String[] { "Homer", "Simpson" };
p.setName(fullname); // 传入fullname数组
System.out.println(p.getName()); // "Homer Simpson"
fullname[0] = "Bart"; // fullname数组的第一个元素修改为"Bart"
System.out.println(p.getName()); // "Homer Simpson"还是"Bart Simpson"?
}
}

class Person {
private String[] name;

public String getName() {
return this.name[0] + " " + this.name[1];
}

public void setName(String[] name) {
this.name = name;
}
}

fullnamename同步更改,原因是new String[]{}创建了一个对象,而fullnamep.name指向了同一个对象。关键是创建了一个对象

构造方法

构造方法初始化实例,构造方法名就是类名无返回值
调用该方法,必须用new操作符

如果既对字段进行初始化,又在构造方法中对字段进行初始化,会发生什么?

在Java中,创建对象实例的时候,按照如下顺序进行初始化:

  • 先初始化字段:int age = 10;表示字段初始化为10,double salary;表示字段默认初始化为0,String name;表示引用类型字段默认初始化为null;

  • 执行构造方法的代码进行初始化。

因此,构造方法的代码是后运行,将覆盖一开始字段初始化。

多构造方法,用法类似方法重载。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person {
private String name;
private int age;

public Person(String name, int age) {
this.name = name;
this.age = age;
}

public Person(String name) {
this.name = name;
this.age = 12;
}

public Person() {
}
}


方法重载(OverLoad):

同一个类里定义几个方法名相同,功能相似但参数不同(参数个数、参数类型不同)的方法

换而言之,以参数内容决定方法内容,省去多个函数名

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
class Hello {
public void hello() {
System.out.println("Hello, world!");
}

public void hello(String name) {
System.out.println("Hello, " + name + "!");
}

public void hello(String name, int age) {
if (age < 18) {
System.out.println("Hi, " + name + "!");
} else {
System.out.println("Hello, " + name + "!");
}
}
}



//当前对象是p1;
p1.distance(p2);
//static?
static double distance(Point c,Point d){}//类是一种数据类型,static静态函数可省略调用对象


其他知识点

this的用法、对象运算符、匿名对象(类)、包和修饰符

this 用法

  • 调用类内的成员变量
    1
    2
    3
    4
    5
    6
    public class MyClass {
    private int num;
    public void setNum(int num) {
    this.num = num;
    }
    }
  • 调用本类中的其他方法

    1
    2
    3
    4
    5
    6
    7
    public class MyClass {
    private int num;

    public void print(MyClass mc) {
    System.out.println(mc.num);
    }
    }
  • 调用本类中的其他构造方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class MyClass {
    private int num;

    public MyClass() {
    this(0);
    }

    public MyClass(int num) {
    this.num = num;
    }
    }

对象运算符(instanceof)

该运算符用于操作对象实例,检查该对象是否是一个特定类型(类类型或接口类型)。

instanceof运算符使用格式如下:

( Object reference variable ) instanceof (class/interface type)
如果运算符左侧变量所指的对象,是操作符右侧类或接口(class/interface)的一个对象,那么结果为真。

1
2
String name = "James";
boolean result = name instanceof String; // 由于 name 是 String 类型,所以返回真

如果被比较的对象兼容于右侧类型,该运算符仍然返回 true。

1
2
3
4
5
6
7
8
9
10

class Vehicle {}

public class Car extends Vehicle {
public static void main(String[] args){
Vehicle a = new Car();
boolean result = a instanceof Car;
System.out.println( result);
}
}

以上实例编译运行结果为:true

匿名对象

普通的类对象在使用时会定义一个类类型的变量,用来保存new出来的类所在的地址。而匿名类取消掉了这个变量,这个地址由编译器来处理,并且在new出来之后,它占用的内存会有JVM自动回收掉。后续无法再使用了。

1
2
3
4
5
6
7
public class Student{
public void classBegin(){
System.out.println("豆zza来喽ヘ(~ω~ヘ)");
}
}

new Student().classBegin();

匿名对象最常用的方式是作为函数的参数,上述的打印语句 “豆zza来喽ヘ(~ω~ヘ)” 是一个匿名对象,由于字符串是以对象的形式存储的,所以这里实际上就是一个没有使用对象引用的匿名对象

匿名类

如果一个内部类在整个操作中只使用一次,就可以定义为匿名内部类。匿名内部类也就是没有名字的内部类,这是java为了方便我们编写程序而设计的一个机制.只创建一个它的对象,以后再不会用到这个类,使用匿名内部类就比较合适。

匿名内部类伴随着接口一起使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public interface USB{
public abstract void open();
public abstract void close();
}

public class Demo{
public static void main(String[] args){
USB usb = new USB(){
public void open(){}
public void close(){}
}

usb.open();
usb.close();

//使用匿名内部类的匿名对象的方式
USB usb = new USB(){
public void open(){}
public void close(){}
}.open();
}
}

在Demo这个类的main方法中创建了一个局部的内部类,这个内部类没有名字,也就是创建了一个匿名内部类。

匿名对象(类)中文本均来自 *Java 学习笔记(8)——匿名对象与内部类

包(package)

  • 将功能相近的类放在同一个包里
  • 某些访问是以包为单位
  • 由于不同包里可能有相同的类名,一定程度上可以避免命名冲突
  • package语句必须是文件中第一条语句
  • WARNING :包没有父子关系。java.util和java.util.zip是不同的包,两者没有任何继承关系。

private、public、protected、无修饰

访问级别访问控制修饰符同类同包子类不同包
公开public
受保护protected×
默认无修饰符××
私有private×××

主要参考: