JavaSE复习day3
胡家伟
10.匿名对象&高内聚低耦合
匿名对象
概念
匿名对象就是没有名字的对象,创建对象时,只在堆内存中开辟空间,不会在栈内存中开辟空间存储堆内存空间的地址。且堆内存中的空间在使用完成后会被立即回收。
用法
-
只调用一次对象的方法时:
new Person().test();
-
作为方法的实际参数或返回值时:
test.testArgs(new Dog());//作为实参 return new Dog();//作为返回值
特点
- 一次调用(每次调用的匿名对象都是新分配的地址空间,都是默认初始值,所以不可能重复使用同一匿名对象)。
- 调用结束后空间会被立即回收,不会产生堆溢出的情况。
- 可以作为形参被调用。匿名对象在作为形参传递到方法内时,调用方法内的作为形参的对象一定是同一个。
高内聚低耦合
模块
模块是从逻辑上将系统分为更细微的部分,将复杂的问题拆成多个简单的问题,逐个解决
耦合主要描述模块之间的关系、内聚主要描述的是模块的内部。模块的粒度可大可小,可以是函数、类、功能块等等。
耦合
模块之间是存在依赖的,这样会导致在改动的时候相互影响,关系越紧密,耦合度就越强,模块独立性就越差
例:若模块A直接操作模块B中的数据,便为强耦合;若A只是通过数据与模块B交互,则视为弱耦合(接口、继承、多态……)
独立的模块便于扩展,维护,写单元测试;如果模块之间重重依赖,就会极大的降低开发效率
内聚
模块内部的元素,关联性越强,内聚越高,模块单一性更强。一个模块应当尽可能独立完成某个功能。
如果多个场景需要被引入到当前模块,代码质量就会变得非常的脆弱。这种情况建议拆分为多个模块
低内聚的模块代码,不管是维护,还是扩展重构都是相当的麻烦。
11.继承
定义
继承是使用已存在的类的定义作为基础建立新类的方式,新类的定义可以增加新的数据(字段)或新的功能(方法),也可以用父类的功能。提升代码的复用性,但是会提高代码的耦合性。
实现
extends
关键字
使用extends
关键字可以使得某一个类继承自一个父类。
[访问修饰符] class [子类名称] extends [父类名称]
{
//子类的代码体
}
例如创建人类、学生、工人,学生和工人继承人类,此时人类是学生和工人的父类(基类、超类),学生和工人是人类的子类(派生类)。
//人类
public class Person {
public String name;
public String sex;
public Person(String name, String sex) {
this.name = name;
this.sex = sex;
}
public Person(){
}
}
//学生
public class Student extends Person{
public int stuId;
public Student(String name, String sex, int stuId) {
super(name, sex);
this.stuId = stuId;
}
public Student(){
}
}
//工人
public class Worker extends Person{
public String job;
public Worker(String name, String sex, String job) {
super(name, sex);
this.job = job;
}
public Worker(){
}
}
继承的限制
- 首先不可以进行多重继承;也就是说一个类同时继承了很多其他的类,在Java中这是不被允许的。但是可以多层的继承,也就是说C继 承自B,B继承自A;这样的做法是被允许的。但是需要注意,即使是这样继承的层叠次数也尽量不要超过三层。
- 从父类继承的私有成员,不能被子类直接使用。子类在继承父类的时候会将父类之中的全部成员(包括属性及方法)继承下来,但是对于所有的非私有(private)成员属于显式继承,而对于所有的私有成员采用隐式继承(即对子类不可见)。子类无法直接操作这些私有 属性,必须通过设置Setter和Getter方法间接操作。所以从理解上这里需要注意,如果一个子类继承自父类,那么会继承来自父类的 一切字段,只是private字段因为访问约束。无法被直接使用。
- 子类在进行对象实例化时,从父类继承而来的数据成员需要先调用父类的构造方法来初始化,然后再用子类的构造方法来初始化本地的数据成员。
- 被final关键字所修饰的类,无法被继承。
实例化子类对象时构造方法的执行方式
-
在实例化一个子类的对象的时候,会默认调用父类的无参数构造方法。
例如A是B的父类,创建B类的实例化对象时,会先调用A的无参构造方法,而后再调用B的构造方法。
-
父类并不具备默认的无参数构造方法时,那么必须在子类中显式地去调用一个父类的构造方法。
例如A类只有有参构造方法,则B类需要使用super()来调用A的有参构造方法。
public A(String name, String sex) { this.name = name; this.sex = sex; } public B(String name, String sex, int id) { super(name, sex); this.id = id; } //先显式调用A的有参构造方法,再调用B的有参构造方法 //注意:super需要放在第一行
super关键字
在之前的类的结构中,我们已经了解到,使用this关键字可以在当前类中用于调用成员内容的时候使用。在继承的环境中,我们可以在子类中使用super关键字调用父类的内容。包括构造方法,方法,字段等。
super | this |
---|---|
1.只能用于调用父类中的成员 2.super代表的是当前类的父类 |
1.专门用于调用当前类中的成员 2.this代表的是子类 3.从父类继承的字段或者方法也可以视为当前类所有,所以在当前类中使用this关键字也可以调用从父类继承过来的内容。 |
方法重写(Override)
在子类中可以将父类的方法重新进行定义,以实现在子类中方法实现新的功能。
-
重写方法的定义名称以及形参列表必须和父类被重写方法的定义完全一致。
-
重写方法的访问修饰符必须要大于等于父类被重写方法的访问修饰符。
public > protected > packaged > private
-
重写方法的返回值类型必须小于等于父类的返回值类型。
说的是引用类型,例如三个类,A类是B类的父类,B类是C类的父类,当父类为B重写方法时,返回类型不能为A。
-
重写方法所抛出的异常类型要小于等于父类抛出的异常类型。
12.final&static
final
final`在Java中被人称之为”终结器“,且通常被final修饰的内容会无法进行修改。
作用
final可以修饰以下五类
-
局部变量:一旦被初始化值不可被二次更改。
final int i = 10; i = 11; System.out.println(i); 输出 java: 无法为最终变量i分配值
-
方法参数:参数值在方法的内部不允许被修改。
//人类 public void say(final String name){ name = "胡家伟"; System.out.println("im a person named" + name); } //主方法 new Person().say("小胡"); 输出 java: 不能分配最终参数name
-
成员变量:要求必须定义这个变量的初始化(可以直接赋值,构造方法),值不允许被更改。
//人类 public final String name; public Person(String name, String sex) { this.name = name; this.sex = sex; } //主方法 Person person = new Person("hu","男"); System.out.println(person); 输出 Person{name='hu', sex='男'} //修改name报错为 java: 无法为最终变量i分配值
-
方法:这个方法不能被子类重写。
方法添加完
final
后,子类无法重写,cannot override,overridden method is final。 -
类:不允许被继承(太监类)
static
静态变量
静态变量存在堆内存中,能被一个类的所有实例对象共享,可以使用类名.变量名的形式来访问。当然也可以先实例化对象再用对象.变量名访问。
//人类
public static String size;
//主方法
Person.size = "normal";
System.out.println(new Person("hu","男").size = "1");
输出
1
静态方法
可以在不创建对象的情况下调用某个方法,使方法和对象解绑。用类名.方法名() 来调用方法。
静态方法中 只能访问用static 修饰的成员。
//人类
public static String size = "1";
public static void test(){
System.out.println(size);
}
//主方法
Person.test();
输出
1
静态代码块
当类被加载时,静态代码块会执行一次,因为一个类只加载一次,所以静态代码块只执行一次。通常使用静态代码块对类的成员变量进行初始化。
在静态代码块中只能访问static修饰的成员
//人类
public static String size;
static {
size = "big";
System.out.println("静态代码块执行");
}
public static void test(){
System.out.println(size);
}
//主方法
Person.test();
输出
静态代码块执行
big
静态内部类
在类的内部定义一个类,用static修饰。可以在不创建外部类对象的情况下被实例化
创建静态内部类的语法格式
外部类名.内部类名 变量名=new 外部类名.内部类名()
class Outer{
private static int num=6;
static class Inner{
void show(){
System.out.println("num="+num);
}
}
}
public class Demo{
public static void main(String[] args){
Outer.Inner inner=new Outer.Inner();//创建内部类对象
inner.show();
}
}
输出
num=6
注意
- static方法:方法体内可以调用其他静态方法,不能调用非静态方法;只可以访问方法外部的static变量;不能定义静态变量,可以定义非静态变量。
- 非static方法:方法体内部不能定义static变量;能调用static方法;能调用非static方法。
- static关键字只能用于修饰成员变量,不能修饰局部变量(如形参、方法体内部变量)。
- 静态内部类中只能访问外部类的静态成员
- 静态内部类中可以定义静态成员,而非静态的内部类中不允许定义静态成员