类,对象
-
类中可以包含:
所有对象所共有的属性/特征--------成员变量
所有对象所共有的行为-------------方法 -
一个类可以创建多个对象
同一类型所创建的对象,结构相同,数据不同 -
类是对象的模板,对象是类的具体的实例
-
补充
-
同一个文件中可以包含多个类
-
public修饰的类只能有一个
-
public修饰的类的名称必须与文件名相同
-
类的构造方法
-
给成员变量赋初值
-
与类同名,没有返回值类型
-
在创建(new)对象时被自动调用
-
若自己没有定义构造方法,则默认一个无参构造方法;
若自己定义了构造方法,则不再默认提供 -
构造方法可以重载
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
- this:
指代当前对象,哪个对象调用方法它指的就是哪个对象
只能用在方法中,方法中访问成员变量之前,默认有个this - this的用法:
1)this.成员变量名-----------访问成员变量
2)this.方法名()--------------调用方法(不用)
3)this()--------------调用构造方法
null
null:空,没有指向任何对象
若引用的值为null,则该引用不能再进行任何操作了,
若操作则发生NullPointerException空指针异常
继承
-
作用:代码复用
-
通过extends来实现继承
-
超类/父类:派生类所共有的属性和行为
派生类/子类:派生类所特有的属性和行为 -
派生类继承超类后,派生类具有:派生类和超类的所有属性和方法
-
一个超类可以有多个派生类,一个派生类只能继承一个超类--------单一继承
(不支持多继承–class C extends A,B—错误!) -
继承具有传递性(多重继承):
A 类继承 B 类,B 类继承 C 类,所以按照关系就是 C 类是 B 类的父类,B 类是 A 类的父类 -
java规定:
在构造派生类之前必须先构造超类;
在派生类的构造方法中若没有调用超类的构造方法,则默认super()调用超类的无参构造方法
在派生类中的构造方法中若调用了超类的构造方法,则不再默认提供
super()调用超类的构造方法必须位于派生类构造方法的第一行
示例:class A{ A(){ } } class B extends A{ B(){ //super();//这句话是默认的 } }
super的用法
1)super.成员变量名---------------访问超类的成员变量
2)super.方法名()-------------------调用超类的方法
3)super()----------------调用超类的构造方法
向上造型
- 超类型的引用指向派生类的对象
- 能点出来什么,看引用的类型
- 向上造型后能访问到的子类成员只有重写的普通方法
package
-
作用:避免类名的冲突
-
包名可以有层次结构(如:包名是oo.day01),同包中的类不能同名
-
类的全称:包名.类名
-
建议:包名所有字母都小写
域名反写 . 项目名称 . 模块名称 . 类名
cn.xxx . projecta . stumanager .
cn.xxx . projecta . teachmanager .
import
-
同包中的类可以直接访问
-
不同包中的类不能直接访问,想访问:
- 先import声明类,再访问类
- 类的全称-------太繁琐、不建议
访问控制修饰符
-
public:公开的,任何类
-
private:私有的,本类
-
protected:受保护的,本类、派生类(子类)、同包类
-
默认的:什么也不写,本类、同包类
说明:
1. 类的访问修饰符只能是public或默认的
2. 类中成员的访问修饰符上面4种都可以
3. 派生类(子类)方法的访问权限要大于或等于超类(父类)方法的
一般情况:
1. 数据(成员变量)私有化(private)
2. 行为(方法)公开化(public)
final
最终的、不能改变的---------------单独应用几率极低
-
修饰变量:变量不能被改变
-
修饰方法:方法不能被重写
-
修饰类:类不能被继承
示例:
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
-
静态变量
- 由static修饰
- 属于类,存储在方法区中,只有一份
- 常常通过类名.来访问
- 何时用:所有对象所共享的数据(图片、音频、视频等)
-
静态方法
- 由static修饰
- 属于类,存储在方法区中,只有一份
- 常常通过类名.来访问
- 静态方法中没有隐式this的传递,静态方法中不能直接访问实例成员
-
静态块
- 由static修饰
- 属于类,在类被加载时自动执行,只执行一次
- 何时用:加载/初始化静态资源(图片、音频、视频等)
-
cookie:
静态变量------------一般在静态块中初始化
实例变量------------一般在构造方法中初始化成员变量:
-
实例变量:没有static修饰,属于对象的,存储在堆中,
有几个对象就有几份
通过对象点来访问 -
静态变量:由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 常量:应用率最高
-
必须声明同时初始化
如:static final int age = 20; -
由类名.来访问,不能被改变
-
建议:常量名所有字母都大写,多个单词用_分隔
-
编译器在编译时会将常量直接替换为具体的值,效率高
(注意:如果是静态变量,会将类Eoo.class加载到方法区中,将静态变量一并存储到方法区中;常量则没有存储过程) -
何时用:数据永远不变,并且经常使用
注意:
- 执行静态块必须加载类,加载类必须是调用构造器或者访问静态成员
- 每次执行构造器前执行实例块
- 静态块优先实例块执行
- 静态块和静态变量没有先后顺序,谁在前面谁先执行
结论:
- 父类静态变量和静态块(先声明的先执行)
- 子类静态变量和静态块(先声明的先执行)
- 父类的变量和代码块(先声明的先执行)
- 父类的构造方法
- 子类的变量和代码块(先声明的先执行)
- 子类的构造方法
示例:
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; //编译错误,常量必须声明同时初始化
}
成员内部类—应用率低
-
类中套类,外面的类称为Outer外部类,里面的类称为Inner内部类
-
内部类通常只服务于外部类,对外不具备可见性(在外面无法访问内部类)
-
内部类对象通常是在外部类中创建的
-
内部类中可以直接访问外部类中的成员(包括私有的)
内部类中有个隐式的引用指向了创建它的外部类对象,语法:外部类名.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属性
}
}
}
匿名内部类:应用率高
-
若想创建一个类(派生类)的对象,并且对象只被创建一次,此时类不必命名,称为匿名内部类
-
在匿名内部类中访问外部的变量,要求该变量必须是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
抽象方法
-
由abstract修饰
-
只有方法的定义,没有具体的实现(连{}都没有)
-
构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。
抽象类
-
由abstract修饰
-
包含抽象方法的类必须是抽象类;不包含抽象方法的类也可以声明为抽象类-----我乐意
-
抽象类不能被实例化
-
抽象类是需要被继承的,派生类(子类需要:)
- 重写所有的抽象方法
- 也可以声明为抽象类------------一般不这么用
-
抽象类的意义:
- 封装派生类共有的属性和行为---------代码复用
- 为所有派生类提供统一的类型--------向上造型
- 可以包含抽象方法,为所有派生类提供统一的入口。(派生类的具体实现不同,但入口是一致的)
设计规则
- 将派生类共有的属性和行为抽到超类中--------抽共性
- 所有派生类的行为都一样,设计为普通方法;所有派生类的行为不一样,设计为抽象方法
- 将部分派生类所共有的行为,抽到接口中。符合既是也是原则时,使用接口,接口是对继承的单根性的扩展----实现多继承
类中的变量
-
实例变量:
1.类中,方法外
2.创建对象时存储在堆中,对象被回收时一并被回收
3.有默认值 -
局部变量:
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;
}
};
来源:CSDN
作者:雨醉东风
链接:https://blog.csdn.net/zhangxuelong461/article/details/103824815