面向对象基本练习题及关键字Static

今天处理了一些面向对象的基本练习题,针对于面向对象解决问题的思路和方法加以理解和消化,回顾并复习了面向对象编程的基本内容。还学习了静态关键词Static的使用方法和特点
1.面向对象编程语言的基本特征是什么
面向对象的三大基本特征是:封装、继承、多态

  • 封装隐藏了类的内部实现机制,从而可以在不影响使用者的前提下改变类的内部结构,同时保护了数据。
  • 继承是为了重用父类代码,同时为实现多态性作准备。
  • 多态性是发送消息给某个对象,让该对象自行决定响应何种行为。通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用。

2.设计一个包含多个构造器的类,并分别用这些构造函数实例化对

  • 构造器方法不能有返回值类型的声明,即使void都不可以
  • public void A(){}不是构造器,是合法的普通方法,可以直接调用 new A().A()
public class A {
    
    
	public A() {
    
    
	} // new A();
//允许构造器方法重载---方法名称相同,参数不同
	public A(int k) {
    
    
	} // new A(123)
	public A(String k) {
    
    
	} // new A("yan")
	public A(int k1, String k2) {
    
    
	} // new A(123,"yan")
	public A(String k1, int k2) {
    
    
	} // new A("yan",123)
}

3.Java语言中,成员变量与局部变量有什么区别

  • 成员变量定义在类中,整个类中都能访问,和具体的定义位置无关
  • 局部变量定义在方法、语句、局部代码块中,只在所属的区域中有效,而且必须是先定义后使用,必须是先赋初值后使用
  • 成员变量存在于堆内存的对象中,堆内存中的对象大小可以任意,并允许在运行时进行调整。所以访问查找的效率比较低
  • 局部变量存在与栈内存的方法中,可以快速定位,但是大小是限定的
  • 成员变量随着对象的创建而存在,随着对象的表示而消失。局部变量随着所属区域的执行而存在,随着所属区域的结束而释放
  • 成员变量都有默认初始化值;局部变量没有默认初始化值

4.编写一个Cal1类实现加减两种运算,然后编写另一个Cal2类实现乘除两种运算

public class Cal1 {
    
    
	private int n1, n2; // 省略了get/set方法
public long add()
	{
    
    // 不会出现空指针问题,因为n1和n2是简单类型,默认值为0
		return 0L + n1 + n2;
	}
	public long sub() {
    
    
		return 0L + n1 - n2;
	}
}
//Cal1 c1=new Cal1(); c1.setN1(100); c1.setN2(200); long res=c1.add();
public class Cal2 extends Cal1 {
    
    
	public double mul() {
    
    
		return 1. * getN1() * getN2();
	}
	public double div() {
    
    
		if (getN2() != 0)
			return 1. * getN1() / getN2();// 如果没有1.这个操作,则是整除计算
		else
			return Double.POSITIVE_INFINITY; // 正负无穷大之分
	}
}

5.建立3个类:居民、成人、官员。居民包含身份证号、姓名、出生日期,而成人继承自居民,多包含学历、职业两项数据,官员则继承自成人,多包含党派、职务两项数据。要求每个类的字段都以属性的方式对外提供数据输入输出的功能
所谓的字段一般用于指代只有属性定义,但是没有get/set方法;属性表示既有对应的private属性声明,同时又对应的get/set方法

public class Resident {
    
    
	private String idCard;// 18位并且可能有字符,数值型数据的比较效率高于字符串
	private String name;
	private Date birth; // java.util.Date是系统提供的日期类型
//get/set方法....
	public void setIdCard(String idCard) {
    
    
//针对传入的身份证号码进行合法性验证,如果数据不合法应该通过异常告知调用处或者赋默认值
		if (idCard != null && idCard.trim().length() == 18)
			this.idCard = idCard;
		else
			throw new RuntimeException("身份证号码不合法!");
	}
}
public class Adult extends Resident {
    
    
	private String education;// 真实实现应该考虑使用枚举类型enum,以保证education的取值范围
	private String vocation;// 职业
//get/set方法....
}
public class Official extends Adult {
    
    
	private String party;
	private String duties;
//get/set方法....
}

6.编写一个控制台应用程序,完成下列功能,并回答提出的问题

  • 创建一个类A,在构造函数中输出“A”,再创建一个类B,再构造函数中输出“B”
  • 从A继承一个名为C的新类,并在C中创建一个成员变量B,不要为C创建构造函数
  • main方法中创建类C的一个对象,写出运行程序后输出的结果
  • 如果在C中也创建一个构造函数输出"C",整个程序运行的结果是什么
//一个文件中可以定义多个类,但是只能有一个public class
//public class到处可见,默认class只能同包可见
public class A {
    
    
	public A() {
    
    
		System.out.println("A");
	}
}
class B {
    
    
	public B() {
    
    
		System.out.println("B");
	}
}
class C extends A {
    
    
	private B b = new B();

	public C() {
    
    
		System.out.println("C");
	}
}
class Test {
    
    
	public static void main(String[] args) {
    
    
		C c = new C();// 输出结果为先A后B
	}
}

6.创建一个类,它存储一个int数据成员,当该数据成员被存储时将其乘以100,当其被读取时将其除以100

public class A {
    
    
	private int data;
	public void setData(int data) {
    
    
		if (data <= Integer.MAX_VALUE / 100)
			this.data = data * 100;
		else
			throw new RuntimeException("数据太大了!");
	}
	public int getData() {
    
    
		return this.data / 100;
	}
}

定义常量

命名规则:名称全大写,下划线分词

  • 声明语法:public static final double MIN_NUMBER = 0.1;
  • 声明的同时直接进行初始化
    public static final double MIN_NUMBER = 0.1;
  • 先声明后在static静态块中赋值
public static final double MIN_NUMBER;
   static{
    
    
    MIN_NUMBER = 0.1;
}

静态方法

因为可以直接使用”类名.方法名”的形式直接调用静态方法,静态方法执行时很有可能并没有构建对象,所以在静态方法中不允许使用this/super之类用于指定对象的关键字

public class B {
    
    
	private Random random;
public static void pp() {
    
    
System.out.println("pp....");
//静态方法的调用没有要求必须构建B对象,所以很有可能random根本不存在,要求在静态方法中不能访问非静态成员
// System.out.println(random);
// 在static方法中不允许出现this或者super关键字
}
	public static void main(String[] args) {
    
    
		B.pp();// 调用当前类中的static方法,可以直接写方法名称pp()
	}
}

当然在静态方法中允许创建对象,并调用对象方法
静态方法只能直接访问静态成员,不能直接访问非静态成员

静态块

public class A {
    
    
	static {
    
     // 类内,所有方法之外
		System.out.println("静态代码块");
	}
}
  • 类在执行时需要通过一个叫作类加载器的组件将程序加载到内存中,类在运行时一般不会发生变化,所以类不会频繁加载,在整个运行过程中只加载一次,而且常驻内存
  • 静态块在类加载完毕后自动执行,而且只执行一次
public class B{
    
    
static {
    
    
      System.out.println("static...");
    }
public static void main(String[] args) {
    
    
    }
}

非静态块

非静态块在类内且在所有的方法之外,非静态块并不会在类加载后自动执行,而是在构建当前对象时自动执行。new一次则会执行一次,执行时机在构造器之前执行

public class A1 {
    
    
	public static B1 bb = new B1();
	static {
    
    
//当类加载完毕自动执行,在整个类的使用过程中只执行一次
//static块和静态属性执行的优先级相同,谁定义时在前先执行谁
		System.out.println("A1.static");
	}
	{
    
    
//在构建对象时自动执行,在这个对象的生命周期中执行且只执行一次
		System.out.println("A1 non static");
	}
//非静态代码块和非静态属性在构造器之前执行
	public A1() {
    
    
		System.out.println("this is A1...");
	}
	public C1 cc = new C1();
	public static void pp() {
    
    
//静态方法只能直接访问静态成员
// System.out.println(age);
		A1 aa = new A1();
		System.out.println(aa.cc);
//不能出现this和super
// System.out.println(this);
		System.out.println(bb);
		System.out.println("this is A1.pp...");
	}
	public static void main(String[] args) {
    
    
// A1.pp();或者 pp();
		A1 aa = new A1();
		A1 aa1 = new A1();
		A1 aa2 = new A1();
	}
}
class B1 {
    
    
	public B1() {
    
    
		System.out.println("this is B1...");
	}
}
class C1 {
    
    
	public C1() {
    
    
		System.out.println("this is C1...");
	}
}
  • 当类加载完毕会自动优先处理static属性和static块,这两个优先级是相同的,所以谁在前先处理谁
  • new对象时,处理非静态属性和非静态块,这两个优先级是相同的,所以谁在前先处理谁
  • 最后执行构造器

使用注意事项

  • 静态方法只能访问静态成员,静态有访问局限性
  • 静态方法中不能有this super关键字
  • 主函数是静态的

什么时候使用静态

  • 当成员变量的数据在当前类的各个对象都相同时,可以用static修饰的,让多个对象共享
  • 非静态方法的调用没特殊要求,构建对象后即可调用;静态方法可以通过类名称直接调用,无需创建对象
  • 非静态方法可以使用静态或者非静态成员;静态方法只能访问静态成员
  • 如果类中的功能都是静态的,那么该类创建对象是没有意义的,所以构造方法需要私有化

static相关问题
父类中定义的静态方法(类方法)是否可以通过”子类名.静态方法名”的方式进行调用?
可以,因为继承的特性

public class Test1 {
    
    
	public static void main(String[] args) {
    
    
		Son.pp();
	}
}
class Fa {
    
    
	public static void pp() {
    
    
		System.out.println("Fa.pp()");
	}
}
class Son extends Fa {
    
    
}

父类中定义的静态方法(类方法)是否可以在子类中进行覆盖定义(重写)?
可以,但是方法签名必须一致,方法必须为static定义

public class Test1 {
    
    
	public static void main(String[] args) {
    
    
		Son.pp();
	}
}
class Fa {
    
    
	public static void pp() {
    
    
		System.out.println("Fa.pp()");
	}
}
class Son extends Fa {
    
    
	public static void pp() {
    
    
		System.out.println("Son.pp()");
	}
}

猜你喜欢

转载自blog.csdn.net/Lecheng_/article/details/112760472