1、第二部分的入门主要集中在类。类的变量分为两种,一种是类拥有的叫成员变量,类的方法可以使用;一种是局部变量,也就是在方法中定义的变量,一般不能跨方法使用。两者之间有一个值得关注的区别是:定义成员变量时如果没有赋值的话,类会给它初始化一个值,比如0;而局部变量定义的时候如果不赋值,不会初始化而是会报错。
2、需要适应记忆的是构造方法的使用,创建对象关键字是new
。
——构造方法是与类名相同但没有返回值的方法
——如果没有自定义构造方法,那么系统会生成一个无参构造方法,会自动调用这个的无参构造方法
——如果有自定义的构造方法,不论是无参的还是有参的,系统都不会自动生成无参构造方法,所以这个时候如果你需要使用无参构造方法,则需要自己手写一遍,相当于手写一个构造方法的重载。
——有参构造函数常用的功能就是给成员变量赋值。
public class Hello {
String name;
int age;
public Hello(){
System.out.println("这个一个无参的构造函数");
}
public Hello(String newName, int newAge){
name = newName;
age = newAge;
System.out.println(name+"这是一个有参的构造函数");
}
}
3、静态变量和静态方法需要注意的是:
——静态方法只能使用静态成员变量,如果需要使用成员变量和方法的话,需要实例化一个对象,通过对象来调用。
——非静态方法则没有这个限制。
4、初始化块与静态初始化块。
——程序运行时静态初始化块最先被执行,然后执行普通初始化块,最后才执行构造方法。
——由于静态初始化块只在类加载时执行一次,所以当再次创建对象 hello2 时并未执行静态初始化块。
5、封装。对属性而言,设置为private的话,我们还是要提供setter和getter方法以供调用和设置的。
public class Hello {
private String name;
public String getName(){
return name;
}
public void setName(String newName){
// 一般IDE都会提供自动创建setter和getter方法,默认的写法是this.name = newName;有this关键字
name = newName;
}
}
6、内部类的目的是什么?主要是为了防止被其他访问。
//外部类HelloWorld
public class HelloWorld {
// 内部类Inner,类Inner在类HelloWorld的内部
public class Inner {
// 内部类的方法
public void show() {
System.out.println("welcome to imooc!");
}
}
public static void main(String[] args) {
// 创建外部类对象
HelloWorld hello = new HelloWorld();
// 创建内部类对象
Inner i = hello.new Inner();
// 调用内部类对象的方法
i.show();
}
}
7、内部类和外部类的详细例子,参考:
——什么是 Java 中的内部类
——Java 中的成员内部类
——Java 中的静态内部类
——Java 中的方法内部类
8、继承。关键字是extends,比如public class Dog extends Animal(){}
。初始化顺序是,先初始化父类再初始化子类,先初始化属性,再初始化构造函数,这也就是我们经常利用构造函数还赋值的原因,因为用属性直接赋值的话会被覆盖掉。
9、final关键字
——修饰类的话,该类不允许被继承
——修饰方法的话,该方法不允许被重载覆写
——修饰属性的话,该属性需要在声明或者构造函数中二选一的初始化
——修饰变量的话,是一个只允许被赋值1次的常量
10、super关键字。其实在子类构造方法初始化过程中默认执行了super()
语句,也就是调用父类的构造方法。
11、Object类,是鼻祖。其中toString方法可被重写,默认是返回对象的地址。IDE工具一般提供toString自动生成功能。
public class Hello {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Hello{" +
"name='" + name + '\'' +
'}';
}
public static void main(String[] args){
Hello h = new Hello();
h.name = "andy";
System.out.println(h);
}
}
——默认的返回值Hello@7440e464
——重写后的结果是Hello{name='andy'}
12、Object类的另一个经常被重写的方法是equals
,默认是比较两个对象是否是同一个对象。但我们常常会用来比较对象的属性值是否相同等。IDE有自动生成功能。
public class Hello {
private String name;
public Hello(String newName){
this.name = newName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Hello)) return false;
Hello hello = (Hello) o;
return name.equals(hello.name);
}
@Override
public int hashCode() {
return name.hashCode();
}
public static void main(String[] args){
Hello h1 = new Hello("Andy");
Hello h2 = new Hello("Andy");
System.out.println(h1.equals(h2));
}
}
——没有重写前,结果是False
——重写后,结果是True
13、多态的概念和应用案例需要多巩固。
——引用类型转换。小类转大类可以直接转,反过来转的话就需要强制转,比如:
Cat c1 = new Cat()
Animal a1 = c1;
Animal a2 = new Animal()
Dog d2 = (Dog)a2
——这里引申的一个知识点就是我们经常会用instanceof
关键字先做个判断之后再转换。
Animal a2 = new Animal()
if(a2 instanceof Dog){
Dog d2 = (Dog)a2
}
14、抽象类。抽象类一般用来约束子类必须要实现的方法。也就是说我们可以在抽象类中定义需要的方法,但不需要实现它,让子类去实现它,只要继承自它的子类都必须要实现这些方法。
public abstract class Hello {
public abstract void call();
public abstract void message();
}
public class Hi extends Hello{
@Override
public void call() {
}
@Override
public void message() {
}
}
15、接口和抽象类的区别
什么时候使用抽象类和接口?
——如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧。
——如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。
——如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。
——书写接口的时候,修饰符可以添加也可以省略abstract,接口中的变量默认都是常量,也就是说默认都会添加public static final,接口中的所有方法都是抽象方法(抽象类中的方法可以是一般方法)。
——如果要继承父类并实现接口,那么继承父类必须要写在前面。
——接口的命名一般在前面增加一个大写的i,及“I”。
public class Dog extends Animal implements interface1,interface2{
}
——接口一般与匿名内部类一起使用
IPlay p = new IPlay(){
@override
// 这里是接口中需要实现的方法
public void play(){
// 代码
}
};
p.play();
或者
new IPlay(){
@override
// 这里是接口中需要实现的方法
public void play(){
// 代码
}
}.play();