Java-类

帅比萌擦擦* 提交于 2020-01-22 16:33:46

类,对象

  • 类中可以包含:
    所有对象所共有的属性/特征--------成员变量
    所有对象所共有的行为-------------方法

  • 一个类可以创建多个对象
    同一类型所创建的对象,结构相同,数据不同

  • 类是对象的模板,对象是类的具体的实例

  • 补充

    1. 同一个文件中可以包含多个类

    2. public修饰的类只能有一个

    3. public修饰的类的名称必须与文件名相同

   

类的构造方法

  1. 给成员变量赋初值

  2. 与类同名,没有返回值类型

  3. 在创建(new)对象时被自动调用

  4. 若自己没有定义构造方法,则默认一个无参构造方法;
    若自己定义了构造方法,则不再默认提供

  5. 构造方法可以重载

    class Student{
    	  String name; //成员变量
    	  int age;
    	  String address;
    	
    	  Student(){
    	    this("无名氏",1,"未知");
    	  }
    	  Student(String name){
    	    this(name,1,"未知");//调用下面的构造方法
    	  }
    	  Student(String name,int age,String address){
    	    this.name = name;
    	    this.age = age;
    	    this.address = address;
    	  }
    	
    	  void study(){          
    	    System.out.println(name+"在学习...");
    	  }
    	  void sayHi(){                    
    	    System.out.println("大家好,我叫"+name+",今年"+age+"岁了,家住"+address);
    	  }
    }
    

this

  1. this:
    指代当前对象,哪个对象调用方法它指的就是哪个对象
    只能用在方法中,方法中访问成员变量之前,默认有个this
  2. this的用法:
    1)this.成员变量名-----------访问成员变量
    2)this.方法名()--------------调用方法(不用)
    3)this()--------------调用构造方法

null

null:空,没有指向任何对象
若引用的值为null,则该引用不能再进行任何操作了,
若操作则发生NullPointerException空指针异常

   

继承

  1. 作用:代码复用

  2. 通过extends来实现继承

  3. 超类/父类:派生类所共有的属性和行为
    派生类/子类:派生类所特有的属性和行为

  4. 派生类继承超类后,派生类具有:派生类和超类的所有属性和方法

  5. 一个超类可以有多个派生类,一个派生类只能继承一个超类--------单一继承
    (不支持多继承–class C extends A,B—错误!)

  6. 继承具有传递性(多重继承):
    A 类继承 B 类,B 类继承 C 类,所以按照关系就是 C 类是 B 类的父类,B 类是 A 类的父类

  7. java规定:
    在构造派生类之前必须先构造超类;
    在派生类的构造方法中若没有调用超类的构造方法,则默认super()调用超类的无参构造方法
    在派生类中的构造方法中若调用了超类的构造方法,则不再默认提供
    super()调用超类的构造方法必须位于派生类构造方法的第一行
    示例:

    class A{
    	A(){
    		
    	}
    }
    class B extends A{
    	B(){
    		//super();//这句话是默认的
    	}
    }
    

super的用法

1)super.成员变量名---------------访问超类的成员变量
2)super.方法名()-------------------调用超类的方法
3)super()----------------调用超类的构造方法

   

向上造型

  1. 超类型的引用指向派生类的对象
  2. 能点出来什么,看引用的类型
  3. 向上造型后能访问到的子类成员只有重写的普通方法

   

package

  1. 作用:避免类名的冲突

  2. 包名可以有层次结构(如:包名是oo.day01),同包中的类不能同名

  3. 类的全称:包名.类名

  4. 建议:包名所有字母都小写
    域名反写 . 项目名称 . 模块名称 . 类名
    cn.xxx . projecta . stumanager .
    cn.xxx . projecta . teachmanager .

import

  1. 同包中的类可以直接访问

  2. 不同包中的类不能直接访问,想访问:

    1. 先import声明类,再访问类
    2. 类的全称-------太繁琐、不建议

   

访问控制修饰符

  1. public:公开的,任何类

  2. private:私有的,本类

  3. protected:受保护的,本类、派生类(子类)、同包类

  4. 默认的:什么也不写,本类、同包类

说明:
1. 类的访问修饰符只能是public或默认的
2. 类中成员的访问修饰符上面4种都可以
3. 派生类(子类)方法的访问权限要大于或等于超类(父类)方法的

一般情况:
1. 数据(成员变量)私有化(private)
2. 行为(方法)公开化(public)

   

final

最终的、不能改变的---------------单独应用几率极低

  1. 修饰变量:变量不能被改变

  2. 修饰方法:方法不能被重写

  3. 修饰类:类不能被继承

示例:

package oo.demo;
//final的演示
public class FinalDemo {
	public static void main(String[] args) {
	
	}
}
//演示final修饰类
final class Joo{}
//class Koo extends Joo{} //编译错误,final的类不能被继承
class Loo{}
final class Moo extends Loo{}

//演示final修饰方法
class Hoo{
	final void show() {}
	void test() {}
}
class Ioo extends Hoo{
	//void show() {} //编译错误,final的方法不能被重写
	void test() {}
}

//演示final修饰变量
/*
 * final修饰成员变量,只有如下两种初始化方式:
 *   1)声明同时初始化
 *   2)在构造方法中初始化
 * final修饰局部变量,只要在用之前初始化即可
 */
class Goo{
	final int num = 5;
	final int count;
	Goo(){
		count = 5;
	}
	void show() {
		final int number;
		//num = 55; //编译错误,final的变量不能被修改
	}
}

   

staic

  1. 静态变量

    1. 由static修饰
    2. 属于类,存储在方法区中,只有一份
    3. 常常通过类名.来访问
    4. 何时用:所有对象所共享的数据(图片、音频、视频等)
  2. 静态方法

    1. 由static修饰
    2. 属于类,存储在方法区中,只有一份
    3. 常常通过类名.来访问
    4. 静态方法中没有隐式this的传递,静态方法中不能直接访问实例成员
  3. 静态块

    1. 由static修饰
    2. 属于类,在类被加载时自动执行,只执行一次
    3. 何时用:加载/初始化静态资源(图片、音频、视频等)
  4. cookie:
    静态变量------------一般在静态块中初始化
    实例变量------------一般在构造方法中初始化

    成员变量:

    1. 实例变量:没有static修饰,属于对象的,存储在堆中,
      有几个对象就有几份
      通过对象点来访问

    2. 静态变量:由static修饰,属于类的,存储在方法区中,
      只有一份
      通过类名点来访问

       java中Math.sqrt是静态方法(只传参数就可以,不需要创建对象)
       double d = Math.sqrt(25);
      

示例:

package oo.demo05;
	//static的演示
	public class StaticDemo {
		public static void main(String[] args) {
			Aoo o1 = new Aoo();
			o1.show(); //1,1
			Aoo o2 = new Aoo();
			o2.show(); //1,2
			Aoo o3 = new Aoo();
			o3.show(); //1,3
			System.out.println(Aoo.b); //常常通过类名点来访问
	
			//Boo.test(); //常常通过类名点来访问
		   
            下面三句话打印出:静态方法 构造方法 构造方法 构造方法
			Coo o1 = new Coo();
			Coo o2 = new Coo();
			Coo o3 = new Coo();//静态方法是存在方法区中的,只有一份
			
		}
	}
	class Aoo{ //演示静态变量
		int a;
		static int b;
		Aoo(){
			a++;
			b++;
		}
		void show() {
			System.out.println(a+","+b);
		}
	}

	class Boo{ //演示静态方法
		int a;
		static int b;
		void show() { //有隐式this
			System.out.println(a); //this.a
			System.out.println(b);  //Boo.b
		}
		static void test() { //没有隐式this
			//静态方法没有隐式this传递
			//没有this就意味着没有对象
			//而实例变量a必须通过对象来问的
			//所以此处编译错误
			//System.out.println(a);
			System.out.println(Boo.b);
		}
	}

	class Coo{ //演示静态块
		static {
			System.out.println("静态块");
		}
		Coo(){
			System.out.println("构造方法");
		}
	}

   

static final 常量:应用率最高

  1. 必须声明同时初始化
    如:static final int age = 20;

  2. 由类名.来访问,不能被改变

  3. 建议:常量名所有字母都大写,多个单词用_分隔

  4. 编译器在编译时会将常量直接替换为具体的值,效率高
    (注意:如果是静态变量,会将类Eoo.class加载到方法区中,将静态变量一并存储到方法区中;常量则没有存储过程)

  5. 何时用:数据永远不变,并且经常使用

注意:
  1. 执行静态块必须加载类,加载类必须是调用构造器或者访问静态成员
  2. 每次执行构造器前执行实例块
  3. 静态块优先实例块执行
  4. 静态块和静态变量没有先后顺序,谁在前面谁先执行
结论:
  1. 父类静态变量和静态块(先声明的先执行)
  2. 子类静态变量和静态块(先声明的先执行)
  3. 父类的变量和代码块(先声明的先执行)
  4. 父类的构造方法
  5. 子类的变量和代码块(先声明的先执行)
  6. 子类的构造方法

示例:

package oo.day05;
//static final常量的演示
public class StaticFinalDemo {
	public static void main(String[] args) {
		System.out.println(Doo.PI); //通过类名点来访问
		//Doo.PI = 3.1415926; //编译错误,常量不能被改变

		//1)加载Eoo.class到方法区
		//2)静态变量num一并存储到方法区中
		//3)到方法区中获取num的值并输出
		System.out.println(Eoo.num);
	
		//编译器在编译时将常量直接替换为具体的值,效率高
		//相当于System.out.println(5);
		System.out.println(Eoo.COUNT);
	
	}
}

class Eoo{
	public static int num = 5; //静态变量
	public static final int COUNT = 5; //常量
}

class Doo{
	public static final double PI = 3.14159;
	//public static final int NUM; //编译错误,常量必须声明同时初始化
}

   

成员内部类—应用率低

  1. 类中套类,外面的类称为Outer外部类,里面的类称为Inner内部类

  2. 内部类通常只服务于外部类,对外不具备可见性(在外面无法访问内部类)

  3. 内部类对象通常是在外部类中创建的

  4. 内部类中可以直接访问外部类中的成员(包括私有的)
    内部类中有个隐式的引用指向了创建它的外部类对象,语法:外部类名.this

示例:

package oo.demo;
//成员内部类的演示
public class InnerClassDemo {
	public static void main(String[] args) {
		Mama m = new Mama();
		//Baby b = new Baby(); //编译错误,内部类对外不具备可见性
	}
}

class Mama{
	private String name;
	void createBaby() {
		Baby b = new Baby(); //内部类对象需要在外部类中创建
	}
	class Baby{
		void showMamaName() {
			System.out.println(name); //内部类中可以直接访问外部类的成员
			System.out.println(Mama.this.name); //隐式的引用(外部类名.this)
			//System.out.println(this.name); //编译错误,this代表当前对象,当前类中没有name属性
		}
	}
}

   

匿名内部类:应用率高

  1. 若想创建一个类(派生类)的对象,并且对象只被创建一次,此时类不必命名,称为匿名内部类

  2. 在匿名内部类中访问外部的变量,要求该变量必须是final的(jdk1.8以前的版本)

示例:

package oo.demo;
//匿名内部类的演示
public class NstInnerClassDemo {
	public static void main(String[] args) {
		//1)创建了Foo的一个派生类,但是没有名字
		//2)创建了该派生类的一个对象,名为o1
		//3)大括号中的为派生类的类体
		Foo o1 = new Foo() {
			//
		};
	
		int num = 5;
		//1)创建了Foo的一个派生类,但是没有名字
		//2)创建了该派生类的对象,名为o2
		//3)大括号中的为派生类的类体
		Foo o2 = new Foo() {
			void test() {
				System.out.println(num); //jdk1.8以前的版本时,要求num必须是final的
			}
		};
	
	}
}
//抽象类,不允许实例化
abstract class Foo{
	//
}
注意:内部类由独立的.class吗?


Mama$Baby.class
NstInnerClassDemo$1.class
NstInnerClassDemo$2.class

   

抽象方法

  1. 由abstract修饰

  2. 只有方法的定义,没有具体的实现(连{}都没有)

  3. 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。

抽象类

  1. 由abstract修饰

  2. 包含抽象方法的类必须是抽象类;不包含抽象方法的类也可以声明为抽象类-----我乐意

  3. 抽象类不能被实例化

  4. 抽象类是需要被继承的,派生类(子类需要:)

    1. 重写所有的抽象方法
    2. 也可以声明为抽象类------------一般不这么用
  5. 抽象类的意义:

    1. 封装派生类共有的属性和行为---------代码复用
    2. 为所有派生类提供统一的类型--------向上造型
    3. 可以包含抽象方法,为所有派生类提供统一的入口。(派生类的具体实现不同,但入口是一致的)

设计规则

  1. 将派生类共有的属性和行为抽到超类中--------抽共性
  2. 所有派生类的行为都一样,设计为普通方法;所有派生类的行为不一样,设计为抽象方法
  3. 将部分派生类所共有的行为,抽到接口中。符合既是也是原则时,使用接口,接口是对继承的单根性的扩展----实现多继承

类中的变量

  1. 实例变量:
    1.类中,方法外
    2.创建对象时存储在堆中,对象被回收时一并被回收
    3.有默认值

  2. 局部变量:
    1.方法中
    2.方法被调用时存储在栈中,方法调用结束时与栈帧一并被清除
    3.没有默认值

局部内部类不能使用该方法的局部变量

public static void main(String[] args) {
/*
 * java有一个语法要求:
 * 当一个方法的局部内部类当中使用了该方法的其他局部变量时,要求这个变量必须是final的
 * JDK8之后,final关键字可以不写,但是这个语法还在。这意味着局部内部类中是不能修改该变量的值的
 * 如果要修改,只能将该变量定义为属性(或挪到该方法之外的其他地方定义)
 */
// final boolean isFinish = false;
Thread download = new Thread() {
	public void run() {
		System.out.println("down:开始下载图片...");
		for(int i=1;i<=100;i++) {
			System.out.println("down:"+i+"%");
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("down:图片下载完毕");
		isFinish = true;
	}
};
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!