Java之面向对象

JavaSE

面向对象

  • 文件名
    • 在一个java文件写两个类:一个基本类,一个测试类
  • 对象
    • 类名 对象名 = new 类名( );
  • 使用成员变量
    • 对象名.变量名
  • 使用成员方法
    • 对象名.方法名(...)
class Demo1_student{
	public static void main(String [] args) {
		Student s = new Student();
        /*
		 * 1. 声明一个引用变量(栈),栈中开辟s
		 * 2. 通过new关键字 在 堆中开辟 存储 Student对象
		 * 3. 通过赋值将堆Student地址传给栈中的s
		 * */
		s.name = "Mephisto";
		s.age = 14;
		s.gender = "Male";
		s.study();
		s.sleep();
		System.out.println("学生姓名:" + s.name + "   "+  "学生性别: "+ s.gender);		
				
	}
}

class Student {
	String name;
	int age;
	String gender;
	public void study() {
	
		System.out.println("学生学习");
		
	}
	public void sleep() {
		System.out.println("学生睡觉");
	}
}

成员变量和局部变量区别:

  • 在类中的位置不同:

    • 成员变量:在类中方法外
    • 局部变量:在方法定义中或方法声明上
  • 在内存中的位置不同:

    • 成员变量: 在堆内存(成员变量属于对象, 对象进 堆内存)
    • 局部变量: 在栈内存(局部变量属于方法, 方法进 栈内存)
  • 生命周期不同

    • 成员变量: 随着对象的创建而存在,随着对象的消失而消失
    • 局部变量: 随着方法的调用而存在,随着方法的调用完毕而消失
  • 初始化值不同

    • 成员变量有默认的初始化值
    • 局部变量没有默认的初始化值, 必须定义,赋值,然后才能使用
  • 注意事项

    • 局部变量名称可以和成员变量名称一样,在方法中使用的时候,采用的就是就近原则
    • 基本数据类型变量包括 byte, short, int , long, float, double, boolean, char
    • 引用数据类型变量包括 数组 类 接口 枚举

面向对象(如何调用对象方法的形式参数是类名)

public class Demo3 {
	public static void main(String [] args) {
		print(10);
		Demo_Student s = new Demo_Student(); //创建对象,并将对象的地址值赋值给s
		print(s);	
	}
	public static void print(int x) {	// 基本数据类型当作形式参数
		System.out.println(x);
	}	
	public static void print(Demo_Student s) {	// 引用数据类型当作形式参数
		s.name = "Mephisto";
		s.age = 22;
		s.speak();
	}
	
}

/*
 * 方法的参数名是类名  public void print(Demo_Student s){}  // print(new Student));
 *  一个方法的形式参数是一个类类型(引用数据类型), 需要的是该类的对象;
 * */




class Demo_Student{
	String name;
	int age;
	public void speak() {
		System.out.println(name + "    " + age);
	}
}

面向对象(匿名对象)

/*
 * 匿名对象: 没有名字的对象
 * 匿名对象应用场景: 调用方法, 仅仅调用一次的时候 , 匿名调用节省代码
 * 调用多次的时候不合适, 匿名对象调用完毕就是垃圾, 可以被垃圾回收器回收
 * 匿名对象可以作为实际参数传递
 */
public class Demo4 {
	
	public static void main(String [] args) {
		/*
		Car c1 = new Car(); // 创建有名字的对象
		c1.run();
		
		
		new Car().run();	// 匿名对象调用方法  , 对方法的一次调用 每次调用产生多个对象
		*/
		
		// 匿名对象是否可以调用属性并赋值? 有什么意义
		
		/*
		 * 匿名对象可以调用属性,但是没有意义, 因为调用之后就变成了垃圾
		 * 如果调用还是用有名字的对象
		
		
			new Car().color = "red";
			new Car().run();
		 
		 */
		
		/*
		Car c1 = new Car();
		c1.color = "red";
		c1.run();
		
		
		Car c2 = new Car();
		c2.color = "yellow";
		c2.run();
		*/
		
		/*
		Car c1 = new Car();
		method(c1);
		
		Car c2 = new Car();
		method(c2);
		
		*/
		
		
		// 匿名对象可以作为实际参数传递
		method(new Car());
		method(new Car());
		
		
	}
	
	// 抽取方法提高代码复用性
	public static void method(Car cc) {
		cc.color = "red";
		cc.run();
	}

}
class Car{
	String color;
	
	public void run() {
		
		System.out.println(color + "车运行起来了");
		
	}
}



面向对象(封装)

  • 封装概述
    • 是指隐藏对象的属性和实现细节, 仅对外公开访问方式
  • 封装好处
    • 隐藏实现细节, 提供公共的访问方式
    • 提高了代码的复用性
    • 提高安全性
  • 封装原则
    • 将不需要对外提供的内容都隐藏起来
    • 把属性隐藏提供公共方法对其访问
  • private关键字特点
    • 是一个权限修饰符
    • 可以修饰成员变量和成员方法
    • 被其修饰的成员只能在本类中被访问
package learn_javaSe;
/*
 * 封装和private的应用:
 * 把成员变量用private修饰
 * 提供对应的getXXX()和setXXX()方法
 * private仅仅是封装的一种形式体现, 不能说封装就是私有
 */
public class Demo5 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Demo5_Person p1 = new Demo5_Person();
		p1.name = "Mephisto";
		/*
		p1.age = -22;
		p1.speak();
		*/
		
		p1.setAge(-22);
		System.out.println(p1.getAge());
	}

}

class Demo5_Person{
	String name;	// 姓名
	private int age;		// 年龄
	
	public void setAge(int a) {	// 设置年龄
		if( a> 0 && a < 200)
			age = a;
		else	
			System.out.println("请输入正常的年龄");
	}
	public int getAge() {		// 获取年龄
		return age;
	}
	
	public void speak() {
		System.out.println(name + "   " + age);
	}
}

面向对象(this关键字)



/*
 * this关键字特点: 代表当前对象的引用
 * 区分成员变量和局部变量
 */



public class Demo6 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Demo6_person p = new Demo6_person();
		p.setName("Mephisto");
		p.setAge(15);
		System.out.println(p.getName() + "  " + p.getAge());
		
		
		Demo6_person p2 = new Demo6_person();
		p2.setName("Vincent");
		p2.setAge(25);
		System.out.println(p2.getName() + "  " + p2.getAge());

	}

}
class Demo6_person{
	
		private String name;	// 姓名
		private int age;		// 年龄
		
		public void setName(String name) {
			this.name = name;
		}
		public String getName() {
			return name;
		}
		
		
		public void setAge(int age) {	// 设置年龄
			if( age> 0 && age < 200)
				this.age = age;
			else	
				System.out.println("请输入正常的年龄");
		}
		public int getAge() {		// 获取年龄
			return age;
		}
}
手机类
package learn_javaSe;

public class Demo7 {

	public static void main(String[] args) {
		Demo7_Phone p =new Demo7_Phone();
		p.setBrand("魅族");
		p.setPrice(2499);
		System.out.println(p.getBrand() + "  " + p.getPrice());
		p.call();
		p.playGame();
		p.sendMessage();
	}
}

/*
 * 手机类:
 * 属性: 品牌brand 价格 price
 * 行为: 打电话call, 发信息 sendMessage 玩游戏 playGame
 */


class Demo7_Phone{			// java bean 
	private String brand; // 品牌
	private int price;	//价格
	
	public void setBrand(String brand) {		// 设置品牌
		this.brand = brand;
	}
	public String getBrand() {		//获取品牌
		return this.brand;		// this.可以省略, 系统默认加上
	}
	public void setPrice(int price) {	// 设置价格
		this.price = price;
	}	
	public int getPrice() { 		// 获取价格
		return price;
	}
	
	public void call() {
		System.out.println("打电话");
		
	}
	public void sendMessage() {
		System.out.println("发短信");
	}
	public void playGame() {
		System.out.println("玩游戏");
	}
	
	
}

构造方法

构造方法: 给对象的数据(属性) 进行初始化

构造方法格式和特点:

​ 方法名与类名相同(大小也和类名一致)

​ 没有返回值类型, 连void也没有

​ 没有具体的返回值 return;

package learn_javaSe;

public class Demo8 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Demo8_Person p = new Demo8_Person();		// 在创建对象的时候就已经调用了构造方法
		//		p.Demo8_Person  // 构造方法不能通过对象调用
		p.show();
	}

}
class Demo8_Person{
	private String name;
	private int age;
	// 构造方法
	public Demo8_Person(){
//		System.out.println("Hello world!");
//		return;		// 构造方法也是有return语句的   格式: return;
		name = "Mephisto";
		age = 10;
		return;
	}
	public void show() {
		System.out.println(name + "  " + age);
	}
	
}

面向对象(构造方法的重载及注意事项)

  • 构造方法的重载:方法名相同,与返回值类型无关(构造方法没有返回值),只看参数列表
  • 注意事项
    • 如果没有给出构造方法, 系统将默认提供一个无参构造方法
    • 如果给出了构造方法,系统将不再提供默认的无参构造方法
      • 还想使用无参构造方法,需要自己给出
public class Demo9 {
	public static void main(String [] args) {
		Demo9_Person p1 = new Demo9_Person();
		p1.show();
		System.out.println("----------------------");
		
		Demo9_Person p2 = new Demo9_Person("Mephisto",18);
		p2.show();
		
		Demo9_Person p3 = new Demo9_Person("Vincent",17);
		p3.show();
		
	}
}

class Demo9_Person{
	private String name;
	private int age;
	
	public Demo9_Person() {
		System.out.println("空参的构造参数");
	}
	
	public Demo9_Person(String name,int age) {
		this.name = name;
		this.age = age;
		
		System.out.println("有参的构造方法");
	}
	
	
	public void show() {
		System.out.println(name + "  " + age);
	}
	
}

构造方法和setXXX()方法区别

public class Demo10 {

	public static void main(String[] args) {
		Demo10_Person p1 = new Demo10_Person("Mephisto",18);
		// p1 = new Demo10_Person("李四",19);  // 重新创建的新对象,不是对原对象的修改,将原对象变成垃圾
		System.out.println(p1.getName()+"   "+ p1.getAge());
		System.out.println("============================");
		
		Demo10_Person p2= new Demo10_Person();
		p2.setName("Vincent");
		p2.setAge(24);
		
		p2.setName("张三");
		System.out.println(p2.getName()+"   "+ p2.getAge());
	}

}
/*
 * 构造方法  给属性进行初始化
 * setXXX()方法  修改属性值, 更加灵活
 */
class Demo10_Person{
	private String name;
	
	private int age;
	
	public Demo10_Person() {
		
	}
	public Demo10_Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
	
	
	public void setAge(int age) {
		this.age = age;
	}
	public int getAge() {
		return age;
	}
	
}
Student s = new Student();
  • Student.class加载进内存
  • 声明一个Student类型引用
  • 在堆内存创建对象
  • 给对象中属性默认初始化值
  • 属性进行显示初始化
  • 构造方法进栈, 对对象中的属性赋值, 构造方法弹栈
  • 将对象的地址值赋值给s

static

static关键字的特点:

  • 随着类的加载而加载
  • 优先于对象的存在
  • 被类的所有对象共享(例如班级号被全班同学共享)
  • 可以通过类名调用
  • 本身可以通过对象名调用
  • 推荐使用类名调用
  • 静态修饰的内容一般我们称其为: 与类相关的, 类成员
public class Demo16 {

	public static void main(String[] args) {
		/*
		Demo16_Person p1 = new Demo16_Person();
		p1.name = "mephisto";
		p1.country = "中国";
		
		
		
		Demo16_Person p2 = new Demo16_Person();
		p2.name = "Vincent";
		
		
		p1.speak();
		p2.speak();
		*/
		Demo16_Person.country = "中国";
		System.out.println(Demo16_Person.country);

	}

}

class Demo16_Person{
	String name;
	static String country; // 静态
	
	public void speak() {
		System.out.println(name + "  " + country);
	}
	
}

static注意事项

package learn_javaSe;

public class Demo17 {

	public static void main(String[] args) {
		Demo17_Test demo = new Demo17_Test();
		demo.print1();

	}

}
/* static的注意事项
 * 在静态方法中是没有this关键字的
 * 静态是随着类的加载而加载,this是随着对象的创建而存在的
 * 静态比对象现存在
 * 静态方法只能访问静态的成员变量和静态的成员方法
 * 静态方法: 
 * 		成员变量: 只能访问静态变量
 * 		成员方法: 只能访问静态成员方法
 * 
 * 非静态方法: 
 * 		成员变量: 可以是静态的, 也可以是非静态的
 * 		成员方法: 可以是静态的成员方法, 也可以是非静态的成员方法
 * 
 * 静态只能访问静态, 静态先于非静态存在
 * 
 */

class Demo17_Test{
	int num1 = 10; 	// 非静态成员变量
	static int num2 = 20; 	// 静态成员变量
	
	public void print1() {	// 非静态的成员方法, 可以访问静态的成员变量也可以访问非静态的成员变量
		System.out.println(num1);
		System.out.println(num2);
	}
	
	
	public static void print2() {	// 静态成员方法
		// System.out.println(num1);	// 静态方法无法访问非静态成员变量
		System.out.println(num2);
	}
	
}

静态变量和成员变量的区别

静态变量也叫类变量, 成员变量也叫对象变量

  • 所属不同
    • 静态变量属于类, 所以也成为类变量
    • 成员变量属于对象, 所以也成为实例变量( 对象变量 )
  • 内存中位置不同
    • 成员变量存储于方法区中的静态区
    • 成员变量存储于堆内存中
  • 内存出项的时间不同
    • 静态变量随着类的加载而加载, 随着类的消失而消失
    • 成员变量随着对象的创建而存在, 随着对象的消失而消失
  • 调用不同
    • 静态变量可以通过类名调用, 也可以同通过对象调用
    • 成员变量只能通过对象名调用
package learn_javaSe;



public class Demo18 {
	public static void main(String [] args) {
		Test18 t1 = new Test18();
		t1.print1();
		String t2 = Test18.name2.toString(); // 静态 变量可以通过类名调用
		System.out.println(t2);
	}
}


class Test18{
	String name1 = "Mephisto";
	static String name2 = "Vincent";
	
	public void print1() {
		System.out.println(name1);
	}
	
	public void print2() {
		System.out.println(name2);
	}
	
}

main方法的格式解释

package learn_javaSe;

public class Demo19 {
	public static void main(String [] args) {
		
		/*
		 * public : 被jvm调用, 所以权限要足够大
		 * static : 被jvm调用, 不需要创建对象名, 直接类名, 调用即可
		 * main   : 只有这样写才能被jvm识别, main不是关键字
		 * String [] args : 以前是用来接受键盘录入的
		 * 
		 */
		
		System.out.println(args.length);
		for(int i = 0; i < args.length; i++) {
			System.out.println(args[i]);
		}
	}

}

如果一个类中所有方法都是静态的, 需要私有构造方法, 私有构造方法之后其他类无法创建该类的对象

文档注释(说明书)

@author 提取作者内容

@version 提取版本内容

@param 参数名称

@return 函数运行完返回的数据

javadoc -d 保存文件 -version -author XXXX.java

代码块

在java中, 使用{ }括起来的代码被称为代码块

代码块分类:
  • 局部代码块 在方法中出现, 限定变量生命周期, 及早释放提高内存利用率
  • 构造代码块 在类方法外出现, 多个构造方法中相同的代码放在一起, 每次调用构造都执行,并且在构造方法前执行
  • 静态代码块
    • 在类中方法外出现, 加了static修饰
    • 在类中方法外出现, 并加上了static修饰,用于给了类进行初始化, 在加载的时候就执行, 并且只执行一次
    • 一般用于加载驱动
  • 同步代码块
package learn_javaSe;

public class Demo23 {

	public static void main(String[] args) {
//		{
//			int x = 10; // 限制变量的生命周期
//			System.out.println(x);
//		}
		
		Test23 stu1 = new Test23();
		System.out.println("---------------");
		Test23 stu2 = new Test23("Mephisto",22);
		System.out.println("---------------");
	}
	
	static {
		System.out.println("主方法类中的静态代码块");   // 优先于主方法执行
	}
}
class Test23{
	private String name;
	private int age;
	
	public Test23() {
		// study();
		System.out.println("空参构造");
	}
	public Test23(String name, int age) {
		// study();
		this.name = name;
		this.age = age;
		System.out.println("有参构造");
	}
	
	public void setName(String name) {
		this.name = name;
	}
	public String getName(){
		return name;
		}
	public void setAge(int age) {
		this.age = age;
	}
	public int getAge() {
		return age;
	}
	{
		// System.out.println("构造代码块");
		study();
	}
	
	public void study() {
		System.out.println("学习");
	}
	static {
		System.out.println("静态代码块");	// 随着类的加载而加载, 且执行一次, 作用: 给类进行初始化, 一般用来加载驱动
	}
}

输出结果
主方法类中的静态代码块
静态代码块
学习
空参构造
---------------
学习
有参构造
---------------
package learn_javaSe;

public class Demo24 {
	static {
		System.out.println("Demo24 静态代码块");
	}
	public static void main(String[] args) {
		System.out.println("main方法");
		
		Test24 t1 = new Test24();
		Test24 t2 = new Test24();

	}

}


class Test24{
	
	static {
		System.out.println("Test24  静态代码块");
		
	}
	{
		System.out.println("Test24  构造代码块");
	}
	public Test24() {
		System.out.println("Test24  构造方法");
	}
	
}

输出结果
Demo24 静态代码块
main方法
Test24  静态代码块
Test24  构造代码块
Test24  构造方法
Test24  构造代码块
Test24  构造方法

继承(extends)

让类和类之间产生关系, 父子关系

package learn_javaSe;

public class Demo25 {

	public static void main(String[] args) {
		Cat c1 = new Cat();
		c1.color = "red";
		c1.leg = 4;
		c1.eat();
		c1.sleep();
		c1.show();
	}

}

class Animal{
	String color;
	int leg;
	
	
	public void eat() {
		System.out.println("吃饭");
	}
	public void sleep() {
		System.out.println("睡觉");
	}
	
	
	public void show() {
		System.out.println(color + " " + leg + " ");
	}
}

class Cat extends Animal{
	

}

class Dog extends Animal{

}

  • 继承的好处

    • 提高代码的复用性
    • 提高代码的维护性
    • 让类与类之间产生了关系, 是多态的前提
  • 继承的弊端

    • 类的耦合性增强了
    • 开发的原则: 高内聚, 低耦合
    • 耦合: 类与类之间的关系
    • 内聚: 就是自己完成某件事情的能力
  • Java中类的继承特点:

    • Java只支持单继承, 不支持多继承 , 多继承有安全隐患

      • 有些语言支持多继承, 格式: extends 类1, 类2 .....
    • Java支持多层继承(继承体系)

      • 使用这个体系使用最底层
      • 想看共性看最顶层
package learn_javaSe;

public class Demo26 {
	public static void main(String [] args) {
		DemoC d = new DemoC();
		d.print();
		d.show();
		d.method();
	}
}


class DemoA{
	public void show() {
		System.out.println("DemoA");
	}
}
class DemoB extends DemoA{
	public void method() {
		System.out.println("DemoB");
	}
}
class DemoC extends DemoB{
	public void print() {
		System.out.println("DemoC");
	}
}
输出结果
DemoC
DemoA
DemoB

继承的注意事项

子类只能继承父类所有非私有的成员(成员方法和成员变量)

子类不能继承父类的构造方法, 但是可以通过super()关键字去访问父类构造方法

不要为了部分功能而去继承

package learn_javaSe;

public class Demo27 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Son s = new Son();
		s.print();

	}

}

/*
 * a: 不同名变量
 * b: 同名变量 
 * 在开发中是不出现子父类同名变量
 * 子类继承父类就是为了使用父类成员, 如果定义了同名的成员变量就没有意义了
 */



class Father{
	int num1 = 10;
	int num2 = 30;
}

class Son extends Father{
	int num2 = 20; 
	public void print() {
		System.out.println(num1);	// 10 
		System.out.println(num2);	// 20   就近原则, 子类有 不用父类
	}
}
输出结果
10
20

this和super的区别

  • this和super都代表什么

    • this, 代表当前对象的引用, 谁来调用我, 我就代表谁
    • super: 表示当前对象父类的引用
  • this和super的使用区别:

    • 调用成员变量:
      • this, 成员变量调用的是本类的成员变量, 也可以调用父类的成员变量
      • super, 成员变量调用父类的成员变量
    • 调用构造方法
      • this(...) 调用本类的构造方法
      • super(...) 调用父类的构造方法
    • 调用成员方法
      • this.成员方法 调用本类的成员方法, 也可以调用父类的成员方法
      • super.成员方法 调用父类的成员方法
    package learn_javaSe;
    
    public class Demo28 {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		Demo28_Son s1 = new Demo28_Son();
    		s1.print();
    	}
    
    }
    
    class Demo28_Father{
    	
    	int num1 = 10;
    	int num2 = 20;
    	
    	
    }
    class Demo28_Son extends Demo28_Father{
    	int num2 = 30;
    	public void print() {
    		System.out.println(num1);
    		System.out.println(num2);
    		System.out.println(super.num2);
    	}
    }
    
    输出结果
    10
    30
    20
    
  • 子类中多有的构造方法默认都会访问父类中空参构造方法

    • 因为子类会继承成父类中的数据, 可能还会使用父类的数据
    • 所以, 子类初始化之前, 一定要完成父类数据的初始化
  • 每个构造方法的第一句默认都是: super() Object类最顶端的父类

package learn_javaSe;

public class Demo29 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Demo29_Son s1 = new Demo29_Son();
		
	}
}
class Demo29_Father{
	public Demo29_Father() {
		super();  // 默认添加super()     访问Object类, Object是最顶层的类
		System.out.println("Father 的构造方法!");
	}
}
class Demo29_Son extends Demo29_Father{
	public Demo29_Son() {
		super();   // 系统默认添加 super(),  用来访问父类中的空参构造
		
		System.out.println("Son的构造方法!");
	}
	
}
输出结果
Father 的构造方法!
Son的构造方法!
  • 父类中没有无参构造怎么办
package learn_javaSe;

public class Demo30 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Demo30_Son s1 = new Demo30_Son();
		System.out.println(s1.getName() + "   " + s1.getAge());
		System.out.println("----------------------");
		Demo30_Son s2 = new Demo30_Son("Mephisto",25);
		System.out.println(s2.getName() + "   " + s2.getAge());
	}

}
class Demo30_Father{
	private String name;
	private int age;
	/*
	public Demo30_Father() {
		// super();
		System.out.println("Father空参构造");
	}
	*/
	public Demo30_Father(String name, int age) {
		// super();
		this.name = name;
		this.age = age;
		System.out.println("Father有参构造");
	}
	
	public void setName(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public int getAge() {
		return age;
	}
	
}

class Demo30_Son extends Demo30_Father{

	public Demo30_Son() {
//		super("Vincent",18);  // 调用父类中的构造方法
		this("Vincent",18);		// 调用本类中的构造方法, 即访问 public Demo30_Son(String name, int age){}
		System.out.println("Son空参构造");
	}

	public Demo30_Son(String name, int age) {
		super(name,age);
		System.out.println("Son有参构造");
	}
}
输出结果
Father有参构造
Son有参构造
Son空参构造
Vincent   18
----------------------
Father有参构造
Son有参构造
Mephisto   25
package learn_javaSe;

public class Demo31 {

	public static void main(String[] args) {
		Zi zi = new Zi();
		zi.show();

	}

}
class Fu{
	public int num = 10;
	
	public Fu() {
		System.out.println("Fu");
	}
}

class Zi extends Fu{
	public int num = 20;
	
	public Zi() {
		System.out.println("Zi");
	}
	
	public void show() {
		int num = 30;
		System.out.println(num);
		System.out.println(this.num);
		System.out.println(super.num);
	}
}
输出结果
Fu
Zi
30
20
10
package learn_javaSe;

public class Demo32 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Demo32_Zi zi = new Demo32_Zi();
	}
	
	/*
	 * 1. JVM 调用了main方法, main进栈
	 * 2. 遇到 Demo32_Zi zi = new Demo32_Zi(); 会先将Demo32_Fu 和 Demo32_Zi加载进内存, 在创建对象
	 * 	     同时父类和子类的静态代码块也会加载进内存  第一个输出时 Fu静态代码块, 第二个输出   Zi静态代码块
	 * 3. 走Demo32_Zi类的构造方法, 因为java中是分层初是化的, 先初始化父类, 然后在初始化父类, 
	 * 	     所以先走父类的构造,但是在执行父类构造时, 发现父类构造代码块, 构造代码块是优先于构造方法执行的
	 * 	     所以第三个输出  Fu构造代码块  第四个输出  Fu构造方法
	 * 4. Demo32_Fu类加载完毕, 加载Demo32_Zi 第五个输出  Zi构造代码块 , 第六个输出  Zi构造方法
	 */
	
	
	
	
}


class Demo32_Fu{
	static {
		System.out.println("Fu静态代码块");
	}
	{
		System.out.println("Fu构造代码块");
	}
	public Demo32_Fu() {
		System.out.println("Fu构造方法");
	}
}
class Demo32_Zi extends Demo32_Fu{
	static {
		System.out.println("Zi静态代码块");
	}
	{
		System.out.println("Zi构造代码块");
	}
	public Demo32_Zi() {
		System.out.println("Zi构造方法");
	}
}

输出结果
Fu静态代码块
Zi静态代码块
Fu构造代码块
Fu构造方法
Zi构造代码块
Zi构造方法
package learn_javaSe;

public class Demo33 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Demo33_Zi z1 = new Demo33_Zi();
		z1.print();
		z1.method();
	}

}

/*
 * 不同名方法
 * 同名方法 
 */


class Demo33_Fu{
	public void print() {
		System.out.println("Fu print");
	}
}
class Demo33_Zi extends Demo33_Fu{
	public void method() {
		System.out.println("Zi method");
	}
	
	
	public void print() { //  重写 
		super.print();	// super可以调用父类的成员方法
		System.out.println("Zi print");
	}
}
输出结果
Fu print
Zi print
Zi method

方法重写

重写: 子父类出现了一模一样的方法(返回值可以时子父类)

当子类需要父类一个功能,而功能主体子类有自己特有的内容时,可以重写父类中的方法, 这样, 即沿袭了父类的功能, 有定义了子类特有的内容

package learn_javaSe;

public class Demo34 {
	public static void main(String[] args) {
		NewPhone p1 = new  NewPhone();
		p1.siri();
		p1.call();
		p1.show();
	}

}

class Demo34_Phone{
	public void call() {
		System.out.println("打电话!");
	}
	public void siri() {
		System.out.println("Speak English!");
	}
	public static void show(){
		System.out.println("Fu static show");
	}
}

class NewPhone extends Demo34_Phone{
	
	public void siri() {
		super.siri();
		System.out.println("说中文");
	}
	
	public static void show() {  // 静态只能覆盖静态,  **看多态
		System.out.println("Zi static show");
	}
}
输出结果
Speak English!
说中文
打电话!
Zi static show
  • 方法重写注意事项
    • 父类中私有方法不能被重写
      • 因为父类私有方法子类根本无法继承
    • 子类重写父类时,访问权限不能更低
      • 最好一致
    • 父类静态方法,子类也必须通过静态方法进行重写
      • 静态只能被覆盖
    • 子类重写父类的时候,最好声明一模一样
  • Override(方法重写)和overload(方法重载)区别
    • Overload可以改变返回值类型, 只看参数列表
    • 方法重写: 子类中出现和父类中方法声明一模一样的方法, 与返回值类型有关, 返回值是一致(或子父类)的
    • 方法重载: 本类中出现和方法名一样, 参数列表不同的方法, 与返回值类型无关
    • 子类调用对象的时候:
      • 先找子类本身, 再找父类

final

  • final修饰特点
    • 修饰类, 类不能被继承
    • 修饰变量变量就成了常量, 只能被赋值一次
    • 修饰方法, 方法不能被重写
package learn_javaSe;

public class Demo37 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Test37 t1 = new Test37();
		t1.print();
		
		double t2 = Test37.PI;	// 访问常量
		System.out.println(t2);
	}

}
class Demo37_Father{
	public final void print() {
		System.out.println("访问底层数据资源");
	}
	
}

/*
class Demo37_Son extends Demo37_Father{
	public void print() {
		System.out.println("哈哈,功能被我干掉了");
	}
}
*/

class Test37{
	final int NUM = 10;  // 常量命名规范, 如果是一个单词, 所有字母大写,如果是多个中间用下划线隔开
	public static final double PI = 3.14; // final 修饰变量被称为常量, 一般跟public static 更好的访问该常量
	public void print() {
		// num = 20;
		System.out.println(NUM);
	}
}
输出结果
10
3.14
  • 基本数据类型, 是之不能被改变的
  • 引用数据类型, 是地址值不能被改变的, 对象中的属性可以改变
package learn_javaSe;

public class Demo38 {

	public static void main(String[] args) {
		final int NUM = 10;
//		NUM = 20;
		System.out.println(NUM);
		
		final Demo38_Person p1 = new Demo38_Person("张三",18);
//		p1  = new Demo38_Person("Vincent",19);
		
		p1.setName("Vincent");
		p1.setAge(19);
		
		System.out.println(p1.getName() + "   " + p1.getAge());
		
		
		method(10);
		method(20);
	}
	
	
	public static void method(final int X) {
		System.out.println(X);
	}
	

}


class Demo38_Person{
	private String name;
	private int age;
	public Demo38_Person() {
		
	}
	public Demo38_Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
	
	public void setAge(int age) {
		this.age = age;
	}
	public int getAge() {
		return age;
	}
}
输出结果
10
Vincent   19
10
20

  • final修饰变量的初始化时
    • 显示初是化
    • 在对象构造完毕前即可
package learn_javaSe;

public class Demo39 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Test39 t1 = new Test39();
		t1.print();
	}

}
class Test39{
	final int num1 = 10; // 显式初始化值
	
	
//	final int num2;   // 成员变量默认初是化值是无效值
	
	final int num3;
	public Test39() {
		num3 = 20; // 在对象构造完成之前进行常量初始化
	}
	public void print() {
		System.out.println(num1);
		System.out.println(num3);
	}
}

多态

  • 事物存在的多种形态
  • 多态前提
    • 要有继承关系
    • 要有方法重写
    • 要有父类引用指向子类对象
public class Demo40 {

	public static void main(String[] args) {
		Demo40_Cat c = new Demo40_Cat();
		c.eat();
		
		Demo40_Animal a = new Demo40_Cat();
		a.eat();
		
	}

}

class Demo40_Animal{
	public void eat() {
		System.out.println("动物吃饭");
	}
}

class Demo40_Cat extends Demo40_Animal{
	public void eat() {
		System.out.println("猫吃鱼");
	}
}
  • 多态中的成员访问特点

    • 成员变量
      • 编译看左边(父类), 运行看左边(父类)
    • 成员方法
      • 编译看左边(父类),运行看右边(子类) (动态绑定)
    • 静态方法
      • 编译看左边(父类), 运行看左边(父类)

    只有非静态成员方法, 编译看父类, 运行看子类

package learn_javaSe;

public class Demo41 {

	public static void main(String[] args) {
		Demo41_Father t = new Demo41_Son();		// 父类引用指向子类对象
		System.out.println(t.num);
		t.print();
		t.method();		// 相当于Demo41_Father.method()
		
		Demo41_Son s = new Demo41_Son();
		System.out.println(s.num);
		s.print();
		s.method();
	}
}
class  Demo41_Father{
	int num = 10;
	public void print() {
		System.out.println("father");
	}
	public static void method() {
		System.out.println("static father");
	}
	
}
class Demo41_Son extends Demo41_Father{
	int num = 20;
	public void print() {
		System.out.println("son");
	}
	public static void method() {
		System.out.println("static son");
	}
}
  • 多态中向下转型和向上转型

Person p = new SuperMan(); 向上转型

SuperMan sm = (SuperMan)p; 向下转型

package learn_javaSe;


public class Demo42 {

	public static void main(String[] args) {
		Demo42_Person person = new Demo42_Superman();	// 父类引用指向子类对象, 超人提升为了人
		person.谈生意();									// 父类引用指向子类对象就是向上转换
		// person.fly();
		Demo42_Superman superman = (Demo42_Superman) person;
		superman.fly();									// 向下转型
		/*
		 * 基本数据类型自动类型提升和强制转换
		 */
		int i = 10;
		byte b = 20;
		i = b;	// 自动类型提升
		b = (byte)i;	// 强制类型转换
		
		
	}

}

class Demo42_Person{
	String name = "John";
	public void 谈生意() {
		System.out.println("谈生意");
	}
}

class Demo42_Superman extends Demo42_Person{
	String name = "Superman";
	
	public void 谈生意() {
		System.out.println("谈几个亿的大单子");
	}
	
	public void fly() {
		System.out.println("会飞");
	}
	
}
  • 多态的好处

    • 提高代码的维护性(由继承保证)

    • 提高代码的扩展性(由多态保证)

      • 可以当作形式参数, 接受任意子类对象
      package learn_javaSe;
      
      public class Demo43 {
      
      	public static void main(String[] args) {
      //		Demo43_Cat c1 = new Demo43_Cat();
      //		c1.eat();
      		method(new Demo43_Cat());
      		method(new Demo43_Dog());
      		
      		// Animal a = new Dog(); // 开发的时候很少在创建对象的时候用父类引用指向子类对象
      		// 直接创建子类对象更方便,可以使用子类中的特有属性和行为
      	}
      	
      	/*
      	public static void method(Demo43_Cat c) {
      		c.eat();
      	}
      	public static void method(Demo43_Dog d) {
      		d.eat();
      	}
      	*/
      	
      	public static void method(Demo43_Animal a) {  // 当作参数的时候,用多态最好, 因为扩展性强
      		// a.eat();
      		// a.lookHome();		// 不能体现子类中特有的属性和行为
      		// 关键字 instaceof   判断前边的引用是否是后边的数据类型
      		if (a instanceof Demo43_Cat) {
      			((Demo43_Cat)a).eat();
      			((Demo43_Cat) a).catchMouse();
      		}else if (a instanceof Demo43_Dog) {
      			((Demo43_Dog)a).eat();
      			((Demo43_Dog)a).lookHome();
      			
      		}else {
      			a.eat();
      		}
      	}
      }
      
      class Demo43_Animal{
      	public void eat() {
      		System.out.println("动物吃饭");
      	}
      	
      }
      class Demo43_Cat extends Demo43_Animal{
      	public void eat() {
      		System.out.println("猫吃鱼");
      	}
      	public void catchMouse() {
      		System.out.println("抓老鼠");
      	}
      }
      class Demo43_Dog extends Demo43_Animal{
      	public void eat() {
      		System.out.println("狗吃肉");
      	}
      	public void lookHome() {
      		System.out.println("看家");
      	}
      }
      
  • 多态弊端

    • 不能使用子类的特有的属性和行为
package learn_javaSe;

public class Demo44 {

	public static void main(String[] args) {
		Demo44_Fu fu = new Demo44_Zi();
//		fu.method();
		fu.show();
		
	}

}
class Demo44_Fu{
	public void show() {
		System.out.println("fu show");
	}
}
class Demo44_Zi extends Demo44_Fu{
	/*
    public void show() {
		System.out.println("zi show");
	}
	*/
	public void method() {
		System.out.println("zi method");
	}
}
输出结果
fu show

抽象类的概述及其特点

  • 抽象就是看不懂

  • 抽象类的特点

    • 抽象类和抽象方法必须用abstract关键词修饰
      • abstract class 类名{}
      • public abstract void demo();
    • 抽象类不一定由抽象方法, 有抽象方法的类一定是抽象类或者是接口
    • 抽象类不能实例化
      • 按照多态的方式, 由具体的子类实例化, 其实这也是多态的一种, 抽象类多态
    • 抽象类的子类
      • 要么是抽象类
      • 要么重写抽象类中的所有抽象方
  • 抽象类成员特点

    • 成员变量,既可以是变量,也可以是常量, abstract不能修饰成员变量
    • 有构造方法, 用于子类访问父类数据的初始化
    • 抽象方法 强制要求子类做的事情
    • 非抽象方法 子类继承的事情, 提高代码复用性
package learnjava;
/**
* @author Mephisto
* @version 2018年7月27日 上午10:40:46
*/
public class Demo3 {

	public static void main(String[] args) {
		Yue yue = new Yue();
		yue.ziG();
	}

}

abstract class AbstractKui{
	public void ziG() {
		System.out.println("用牙签");
	}
}

class Yue extends AbstractDemo{
	public void ziG() {
		System.out.println("用指甲刀");
	}
}
class Lin extends AbstractDemo{
	public void ziG() {
		System.out.println("用锤子");
		
	}
}

一个抽象类如果没有抽象方法, 可以有抽象类, 这么做的目的只有一个,就是不让其他类创建本类对象,交给子类完成

abstract不能和那些关键字共存?

  • abstract 和static
  • 被abstract修饰的方法没有方法体
  • 被static修饰的可以用类名.调用,但是类名.抽象方法是没有意义的
  • abstract 和 final
  • 被abstract修饰的方法强制子类重写
  • 被final修饰的不让子类重写,所以他俩矛盾
  • abstract和private
  • 被abstract修饰的是为了让子类看到并强制重写
  • 被private修饰不让子类访问,所以他俩是矛盾的

接口

从狭义的角度, java中的interface

从广义的角度, 对外提供规则的都是接口

  • 特点
    • 关键词interface
      • interface 接口名 {}
    • 类实现接口用implements表示
      • class 类名 implements 接口名 {}
    • 接口不能实现实例化
      • 按照多态的方式来实例化
    • 接口的子类
      • 可以是抽象类, 但是意义不大
      • 可以是具体类, 要重写接口中的所有抽象方法(推荐方案)
package learnjava;
/**
* @author Mephisto
* @version 2018年7月27日 下午2:28:48
*/
public class Demo8 {

	public static void main(String[] args) {
		// Demo8Inter name = new // Demo8Inter();  // 接口不能被实例化, 因为调用抽象方法没有意义
		Demo8Inter inter = new Demo8Test();	// 父类引用指向子类对象
		inter.print();
		
	}

}

interface Demo8Inter{
	/**
	 * print
	 */
	public abstract void print();		//接口中的方法都是抽象的
}

class Demo8Test implements Demo8Inter{
	@Override
	public void print() {
		System.out.println("这是类实现接口");
	}
}
  • 接口成员变量
    • 这能是常量, 并且是静态的并且是公共的
    • 默认修饰符 public static final
  • 接口是没有构造方法的 一个类如果不写继承任何类,默认继承Object类
  • 接口成员方法 只能是抽象的 默认修饰符 public abstract
类与类, 类与接口, 接口与接口
  • 类与类
    • 继承关系, 只能单继承, 可以多层继承
  • 类与接口
    • 实现关系, 可以单实现, 也可以多实现
    • 并且还可以在继承一个类的同时实现多个接口
  • 接口与接口
    • 继承关系, 可以单继承, 也可以多层继承
package learnjava;
/**
* @author Mephisto
* @version 2018年7月27日 下午2:45:41
*/
public class Demo10 {

	public static void main(String[] args) {
		Demo10Test test = new Demo10Test();
		test.printA();
		test.printB();
	}

}

interface Demo10InterA{	
	/**
	 * printA
	 */
	void printA();
}

interface Demo10InterB{
	/**
	 * printB
	 */
	void printB();
}

interface Demo10InterC extends Demo10InterA,Demo10InterB{
}



class Demo10Test extends Object implements Demo10InterA,Demo10InterB{
	@Override
	public void printA() {
		System.out.println("printA");
	}
	@Override
	public void printB() {
		System.out.println("printB");
	}
}

抽象类和接口的区别
  • 成员区别
    • 抽象类:
      • 成员变量: 可以变量, 也可以常量
      • 构造方法: 有
      • 成员方法: 可以抽象, 也可以非抽象
    • 接口:
      • 成员变量: 只可以常量
      • 成员方法: 只可以抽象
  • 关系区别
    • 类与类
      • 继承, 单继承
    • 类与接口
      • 实现, 单实现, 多实现
    • 接口与接口
      • 继承, 单继承, 多继承
  • 设计理念区别
    • 抽象类 被继承体现的是 : "is a" 的关系, 抽象类中定义的是该继承体系中的共性功能
    • 接口 被实现体现的是:"like a" 的关系, 接口中定义的是该继承体系的扩展功能

package关键字

将字节码(.class)进行分类存放

包其实就是文件夹

域名倒写 com.xxxx.功能名(或模块名)

  • 分类
    • 按照功能划分
    • 按照模块划分
  • 定义包的格式
    • package 包名
    • 多级包用.分开
  • 定义包的注意事项
    • package语句必须是程序的第一条可执行的代码
    • package语句在一个java文件中只能有一个
    • 如果没有package, 默认表示无包名

import关键字

  • import其实就是让有包的类对调用者可见,不用写全类名
  • package import class

四种权限修饰符

修饰符 本类 同一个包下(子类和无关类) 不同包下(子类) 不同包下(无关类)
private Y
默认 Y Y
protected Y Y Y
public Y Y Y Y
  • protected 关键字是只有这个类的子类可以访问
  • default即不写修饰符, 那就只有子类, 跟同一个包的类可以访问
  • private只有类本身可以访问
  • public 所有类都能访问

类及其组成所使用的常见修饰符

  • 修饰符
    • 权限修饰符:private , default, protected, public
    • 状态修饰符:static , final
    • 抽象修饰符:abstract
    • 权限修饰符:default,public
    • 状态修饰符:final
    • 抽象修饰符:abstract
    • 用的最多的public
  • 成员变量
    • 权限修饰符: private default protected public
    • 状态修饰符: static final
    • 用的最多的private
  • 构造方法
    • 权限修饰符: private default protected public
    • 用的最多的 public
  • 成员方法
    • 权限修饰符 private default protected public
    • 状态修饰符 static final
    • 用的最多的 public
  • 除此以外的组合规则
    • 成员变量 public static final
    • 成员方法 public static

内部类

  • 特点
    • 内部可以直接访问外部类的成员, 包括私有
    • 外部类需要访问内部类的成员必须创建对象
    • 外部类名.内部类名 对象名 = 外部类对象.内部类对象;
package learnjava;
/**
* @author Mephisto
* @version 2018年7月28日 上午11:01:25
*/
public class Demo12 {

	public static void main(String[] args) {
		/** 创建内部类对象 */
		Outer12.Inner12 inner = new Outer12().new Inner12();  
		inner.method();
	}

}

class Outer12{
	private int num = 10;
	class Inner12{
		public void method() {
			System.out.println(num);
		}
	}
}
package learnjava;
/**
* @author Mephisto
* @version 2018年7月28日 上午11:01:25
*/
public class Demo12 {

	public static void main(String[] args) {
		/* 创建内部类对象 */
//		Outer12.Inner12 inner = new Outer12().new Inner12();  
//		inner.method();
		
		Outer12 outer12 = new Outer12();
		outer12.print();
	}

}

class Outer12{
	private int num = 10;
    
    /* 成员方法被私有 */
	private class Inner12{
		public void method() {
			System.out.println(num);
		}
	}
    
	public void print() {
		Inner12 inner12 = new Inner12();
		inner12.method();
	}
}
package learnjava;
/**
* @author Mephisto
* @version 2018年7月28日 上午11:12:08
*/
public class Demo13 {

	public static void main(String[] args) {
		
		/** 外部类名.内部类名  对象名  = 外部类名.内部类对象; */
		Outer13.Inner oInner = new Outer13.Inner();
		oInner.method();
		
		Outer13.Inner2.print();

	}

}

class Outer13 {
	static class Inner{
		public void method() {
			System.out.println("method");
		}
	}
	
	
	static class Inner2{
		public static void print() {
			System.out.println("print");
		}
	}
}
package learnjava;

import java.io.IOError;

/**
* @author Mephisto
* @version 2018年7月28日 上午11:19:42
*/
public class Demo14 {

	public static void main(String[] args) {
		Outer14.Inner14 oi = new Outer14().new Inner14();
		oi.show();

	}

}

class Outer14{
	public int num = 10;
	class Inner14{
		public int num = 20;
		public void show() {
			int num = 30;
			/** 要求: 使用已知的变量,在控制台输出10,20,30 */
			/*
			 * 内部类之所以能够获取到外部类的成员, 是因为他能获取到外部类的引用外部类名.this
			 */
			System.out.println(Outer14.this.num);
			System.out.println(this.num);
			System.out.println(num);;
		}
	}
}

局部内部类访问局部变量的问题

  • 局部内部类访问局部变量必须使用final修饰
  • 局部内部类在访问他所在的方法中的局部变量必须使用final修饰
  • 因为当调用这个方法时,局部变量如果没有用final修饰,他的生命周期和方法的生命周期是一样的,当方法弹栈,这个局部变量也会消失,那么如果这个局部内部类对象还没有马上消失享用这个局部变量,就没有了,如果final修饰会在类加载的时候进入变量池,即使方法弹栈,常量池的常量还在,也可以继续使用
    • 在jdk1.8取消了这件事

匿名内部类

  • 就是内部类的简化写法

  • 前提: 存在一个类或接口(这里的类可以事具体类也可以是抽象类

  • 格式:

    new 类名或者接口名(){   
        重写方法; 
    }
    
  • 本质

    • 是一个继承类该类或者实现了该接口的子类匿名对象
package learnjava;
/**
* @author Mephisto
* @version 2018年7月28日 上午11:44:12
*/
public class Demo16 {

	public static void main(String[] args) {
		Outer16 o = new Outer16();
		o.method();

	}

}
interface Inter16{
	/**
	 * print
	 */
	abstract void print();
	
}

class Outer16 {
	/*
	class Inner16 implements Inter16{
		@Override
		public void print() {
			System.out.println("print");
		}
	}
	*/
	public void method(){
		/**
		Inner16 inner16 = new Inner16();
		inner16.print();
		*/
		new Inter16() {			// 实现Inter16 接口	
			@Override			// 重写方法
			public void print() {
				System.out.println("Hello world!");
			}
		}.print();
	}
	
}
package learnjava;
/**
* @author Mephisto
* @version 2018年7月28日 上午11:58:53
*/
public class Demo18 {

	public static void main(String[] args) {
		Outer18 o = new Outer18();
		o.method();
	}

}
interface Inter18{
	public abstract void show1();
	public abstract void show2();
	
}

/** 匿名内部类只针对重写一个方法时候使用  */
class Outer18{
	public void method(){
		/**
		new Inter18() {
			
			@Override
			public void show2() {
				System.out.println("show2");
			}
			
			@Override
			public void show1() {
				System.out.println("show1");
			}
		}.show1();
		new Inter18() {
			
			@Override
			public void show2() {
				System.out.println("show2");
			}
			
			@Override
			public void show1() {
				System.out.println("show1");
			}
		}.show2();
		*/
		
		Inter18 i = new Inter18() {
			
			@Override
			public void show2() {
				System.out.println("show2");
			}
			
			@Override
			public void show1() {
				System.out.println("show2");
			}
			
			/*
			public void show3() {
				System.out.println("show3");
			}
			*/
		};
		i.show1();
		i.show2();
//		i.show3();	// 匿名内部类不能向下强转, 因为没有子类类名
		
		
	}
}
原文地址:https://www.cnblogs.com/mephisto03/p/9381651.html