Java类的高级特性
# Java类的高级特性
# 类
# 成员变量
成员变量是 类中的属性
public class tuzi {
String eat; //吃
String hair; //毛
String jump; //跳
}
# 局部变量
局部变量是 方法或{}括号 内定义的变量
public class jububianliang {
public static void main(String[] args) {
int i = 2,j = 4;
System.out.private(max(i,j));
}
//成员方法
public int max(int a , int b ){
//局部变量max。max变量限于该方法的范围
int max = 0;
if(a > b){
max = a;
return max;
}else{
max = b;
return max;}
}
}
# 成员方法
成员方法是 类的功能(行为)
权限修饰符 返回值类型 方法名(参数类型 参数名[,···){
···· //方法体
return 返回的值;
}
//例子
public int max(int a , int b){
if(a > b){
return a;
}else{
return b;
}
}
如果方法返回类型为void,则无返回空
# this关键字
this关键字 用于当前对象本身 , 一般用于调用自身的成员变量和方法 , 将方法的参数值赋予类本身的成员变量
public class thsiches {
String str = "abc";
public void no1(String str) {
//打印 str形参
System.out.println("no1:"+str);
//打印 thsiches类 中的str成员变量
System.out.println("no2:"+this.str);
}
public static void main(String[] args) {
String str2 = "123";
new thsiches().no1(str2);
}
}
# super关键字
super关键字可以调用父类的 属性/方法
应方式 | 父类成员 属性&方法 |
---|---|
super() | 父类构造方法 |
super.name (name成员变量) | 父类的属性(成员变量) |
super.run() (run()成员方法) | 父类的方法 |
**注意 : **
- 只要是构造方法都会默认 第一行 为
super();
(不管是什么类,都是Object的父类) - 父类有参构造方法需要
super
调用父类构造方法 - 用
private
修饰的成员,其他类无法 调用和重写
super实例:
public class Demo {
public static void main(String[] args) {
new B("");
}
}
class A{
String a;
// 构造方法
public A(String a) {
System.out.println("A有参构造方法");
this.a = a;
}
}
class B extends A{
// B构造方法
public B(String a) {
super(a);
System.out.println("B有参构造方法");
}
}
/* 执行结果
A有参构造方法
B有参构造方法
*/
# this和super区别
this
: 当前对象的引用
super
: 当前对象的父对象的引用
# 构造方法
构造器是类的特殊方法,专门用于在类被实例时,定义初始化类的成员属性所使用(无需再次set方法)
构造方法特点
- 没有返回值
- 方法名与类名相同
- 没有定义构造方法,会自动生成无参数构造方法
- 实例化对象,类都会自动调用 构造方法
- 在无参构造方法
this
调用有参构造方法,则该语句必须为第一个 - 可重载构造器
重载构造器参数应用
- 参数顺序
- 参数类型
# 包
Java JDK API中提供了类功能,它们封装为类包
# 类名冲突
JDK API 中提供的类,在同一类包 同类名 会导致编译器无法执行 ,要把类包分开或更改类名
# 完整的类路径
完整的类名需要包名与类名的组合
java.包名.类名
//例子
java.lang.String
如果指定路径不确定可能会翻车,像以下是需要完整路径 ==java.util.Date date = new java.util.Date();== ==java.sql.Date date2 = new java.sql.Date();==
# 包的特性
把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用
包如同文件夹一样,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名 加以区别。因此,包可以避免名字冲突
包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类
Java包是为了防止命名冲突,访问控制,提供搜索和定位类、接口、枚举和注释等
没有定义包会自动归纳在预设包(默认包)中,最好为所有类设置包名(良好习惯)
package 包名.包名...;
注意:
在类中指定包名时,需要将
package
表达式 放在程序的第一行 (非注释Java包的命名规则是全部使用小写字母的
# import 导入包
引入包可以调用包中的方法,不能调用两包中的同类名,指定包后面有 *
,指定包路径中的所有类
# import 导入静态成员
调用指定
import static 静态成员
例子:
==java.lang.System== 类中的 out成员变量 ==java.lang.Math== 类中的 max成员方法
它们都是静态成员,这是前提!!!
import static java.lang.System.*; //导入静态成员方法
import static java.lang.Math.*; //导入静态成员变量
public class Demo2 {
public static void main(String[] args) {
//静态成员简写调用
out.println("123");
System.out.println("123");
//静态方法简写调用
out.println("max(3,4)?"+max(3,4));
out.println("max(3,4)?"+Math.max(3,4));
}
}
/* 运行结果
123
123
max(3,4)?4
max(3,4)?4
*/
包的使用规则
- 包中Java文件的定义:
在
.java
文件的首部, 必须编写类所属哪个包 - 包的定义:
所有包的名称都由小写字母, 单词与单词之间使用
.
隔开 ,一般命名为==com.公司名.项目 名.模块名....== - 规范由来: 由于Java面向对象的特性,每名Java开发人员都可以编写属于自己的Java包,为了保障每个Java Package命名的唯一性。由于 互联网上 的域名称是不会重复的,因此很多开发者都会采用自己公司的名称作为前缀。例如: ==com.java.xxx==
# 权限修饰符
权限修饰符控制 类/成员变量/成员方法 的访问,不同的权限指定的不同范围
修饰符 | 类 | 包 | 子类 | 其他包 |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
default | √ | √ | × | × |
private | √ | × | × | × |
注意: 类不使用修饰符时,则该类预设为包存取范围
# final 常量
被final修饰,表明改对象是专一的(不能有第三方)
特点:
变量 不能被更改
方法 不能被重写
类 不能被继承
# final变量
final
修饰后, 不能更改该变量的值,该变量称为常量!
final 数据类型 变量名 = 值;
# final方法
final
修饰的方法 不能 重写
private
修饰的方法隐式被指定为 final
,可无需添加 final
[修饰符] final 数据类型 方法名([参数]){···}
# final类
被final修饰的方法类,不能被继承 (跟部分API类类似)
final class 类名{···}
示例:
public class Demo {
// final修饰变量 测试
final int a = 1;
// a 变量不能被修改(报红)
// a = 2;
}
// final修饰方法 测试
class A{
public final void test(){}
}
class B extends A{
// A中的test方法 不能继承(报红)
// public void test(){}
}
// final修饰类 测试
final class AA{ }
// AA 不能被继承(报红)
// class B extends AA{}
# final 总结
修饰对象 | 说明 |
---|---|
变量 | 变量只能初始化赋值 |
方法 | 方法不能被重写 |
类 | 类不能被继承 |
# static 静态
静态修饰的代码,整个程序运行结束之后才会释放
静态特点:
- 静态的数据都是共享的,其他类调用不需实例化进行应用
- 静态在内存中永远只有一份,无论有多个对象
- 静态不能访问非静态,而非静态可访问静态(静态方法)
- 加载时静态总会优先于非静态
# 静态变量
静态变量的共享,在不同类对同一变量可以进行操作
public class Demo {
private static String stu1 = "hello";
public static void main(String[] args) {
String stu2 = "world";
// 直接访问变量
System.out.println("直接访问:"+stu1+stu2);
// 类访问变量
System.out.println("通过类访问:"+Demo.stu1+stu2);
// 通过对象访问变量 (静态被赋值)
Demo demo = new Demo();
demo.stu1 += stu2;
System.out.println("通过对象访问:"+demo.stu1);
// 通过对象访问变量2 通过相同变量进行测试
Demo demo1 = new Demo();
System.out.println("通过对象访问:"+demo1.stu1+stu2);
System.out.println("\n 静态值为:"+stu1);
}
}
/* 运行结果
直接访问:helloworld
通过类访问:helloworld
通过对象访问:helloworld
通过对象访问:helloworldworld
静态值为:helloworld
*/
# 静态变量与实例变量的区别
静态变量 | 实例变量 | |
---|---|---|
内存开辟时期 | 类加载时 | 对象实例时 |
内存分配区域 | 方法独有静态区 | 实例对象堆中 |
类内部访问变量 | 类内的任何方法可直接访问 | 只能访问非静态方法 |
类外部访问变量 | 通过类名进行访问 ==类型.静态变量名== | 通过类的实例对象进行访问 |
# 静态方法
静态方法无需创建类的对象
public class Method {
// 静态方法
public static void test1() {
System.out.println("静态方法");
}
// 实例方法
public void test2() {
System.out.println("实例方法");
}
public static void main(String[] args) {
// 静态直接调用
System.out.println("静态直接调用!");
test1();
// test2(); (报红)
// 实例对象调用
System.out.println("\n实例对象调用!");
Method method = new Method();
method.test1();
method.test2();
// 通过类名调用
System.out.println("\n通过类名调用!");
Method.test1();
// Method.test2();
}
}
/* 运行结果
静态直接调用!
静态方法
实例对象调用!
静态方法
实例方法
通过类名调用!
静态方法
* */
# 静态方法与实例方法的区别
静态方法:
- 不能访问类中的非静态成员(方法,变量)
this
不能访问非静态成员super
不能访问构造器
实例方法:
- 在内部可直接访问
- 在类外部需实例访问
- 在静态方法内需要实例访问
# 内部类
一个类中再定义一个类,在类中再定义的类 称为内部类
特点:
- 内部类仍是个独立的类,在编译之后内部类会被编译成独立的
.class
文件 - 外部类以外需要实例内部类需要外部类指定内部类进行实例 ==外部类名.内部类==
- 内部类是外部类的成员,内部类可外部类的成员,哪怕是
private
也可访问 - 内部类声明成静态,就不能访问外部类的成员,只能访问外部类的静态成员
- 内部类不能与外部类重名
- 内部类访问与外部类 同名的变量时,则需要 ==外部类名.this.变量名== 进行访问成员
# 成员内部类
可直接使用所在的类中的 成员方法/成员变量
注意:
- 在外部类外和非静态方法外实例内部类对象,需要外部类指定该对象才能应用内部类
- 访问被
private
修饰的内部类方法,需要接口重写调用 this
调用本类的成员变量,外部类需要类名作为前缀(需要完整类路径)
public class Outer {
// 实例内部类
class Inner { }
}
示例:
// 外部类
public class OuterVariable {
// 外部类 成员变量
public int i = 111;
private int j = 222;
// 内部类
class Inner {
// 内部类 成员变量
private int i = 333;
private int j = 444;
// 直接访问
public void goInVariable(int i , int j){
//共用外类的变量
System.out.println("内部类 直接变量:");
System.out.println("i : " + i);
System.out.println("j : " + j);
System.out.println("内部类 访问内部类成员变量");
System.out.println("this.i : " + this.i);
System.out.println("this.j : " + this.j);
System.out.println("内部类 类指定访问外部类成员变量:");
System.out.println("OuterVariable.this.i : " + OuterVariable.this.i);
System.out.println("OuterVariable.this.j : " + OuterVariable.this.j);
}
// 直接访问 外部类方法
private void privateTest1(){
//父类.本身.方法();
privateTest();
}
// 指定类访问 外部类方法
private void privateTest2(){
//父类.本身.方法();
OuterVariable.this.privateTest();
}
}
private void privateTest(){
System.out.println("外部类 privateTest()方法!");
}
public static void main(String[] args) {
// 实例 外部类&内部类
OuterVariable outerVariable = new OuterVariable();
Inner inner = outerVariable.new Inner();
// 内部类 访问 外部变量
inner.goInVariable(555,666);
// 内部类 访问 外部方法
inner.privateTest1();
inner.privateTest2();
}
}
/* 运行结果
内部类 直接变量:
i : 555
j : 666
内部类 访问内部类成员变量
this.i : 333
this.j : 444
内部类访问 类指定访问外部类成员变量:
OuterVariable.this.i : 111
OuterVariable.this.j : 222
外部类 privateTest()方法!
外部类 privateTest()方法!
*/
# 局部内部类
局部内部类是指 类定义在 方法/任意作用域 中的类
特点:
- 局部内部类与局部变量一样,不能使用以上修饰
public
/private
/protected
/static
- 局部内部类只在当前方法中有效
- 局部内部类中不能定义
static
- 局部内部类中可访问外部类的所有成员
- 局部内部类中只可访问当前方法中
final
变量
public class Test {
public void method() {
// 局部内部类
class Inner { }
}
}
示例:
public class OuterPart {
int a = 10;
public void method(){
// 局部内部类
class Inner{
int a = 20;
public void print(int a){
System.out.println("a : " + a);
System.out.println("this.a : " + this.a);
System.out.println("OuterPart.this.a : " + OuterPart.this.a);
}
}
Inner inner = new Inner();
inner.print(30);
}
public static void main(String[] args) {
// OuterPart.Inner inner = new OuterPart().new Inner(); (报红)
new OuterPart().method();
}
}
/* 运行结果
a : 30
this.a : 20
OuterPart.this.a : 10
*/
# 匿名内部类
匿名内部类没有类名,必须在创建时使用 new
来声明类
特点:
- 匿名内部类只能够调用一次
- 匿名对象只在堆内存中开辟空间
- 每次创建匿名对象都是不同对象
- 匿名类和局部内部类一样,可以访问外部类的所有成员
- 匿名类中允许使用非静态代码块进行成员初始化操作
- 匿名类的非静态代码块会在父类的构造方法之后被执行
- 使用匿名内部类时,必须是 继承类/实现接口
- 匿名内部类 不能定义构造函数
- 匿名内部类 不能存在静态成员
new <类/接口>() {
// 实现区
};
示例:
interface Port {
void show();
}
public class OuterAnonymous {
public static void main(String[] args) {
// 匿名内部类
// 写法1
Port app = new Port() {
@Override
public void show() {
System.out.println("测试1 匿名内部类!!");
}
};
app.show();
/** 写法2
* lambda表达式 1.8新特性
* (该用法限于实现一个方法的情况使用)
*/
Port app2 = () -> System.out.println("测试2 匿名内部类!!");
app2.show();
}
}
/* 运行结果:
测试1 匿名内部类!!
测试2 匿名内部类!!
*/
# lambda表达式
lambda表达式 也是一个匿名函数
特点:
- 只能应用于 接口 的实现
- 只能应用于 实现一个抽象方法
// 前提需要有 抽象方法
new 接口名([参数]) -> {
// 实现区
};
lambda其他应用说明:
- 参数无需指定数据类型,因抽象方法已经指定参数的数据类型以及个数
- lambda表达式 只能应用于实现一个抽象方法,多个方法则不能应用
应用实例:
- 一个参数 (变量随意,一个参数无需添加括号)
Port app = a ->{ //实现区 };
- 两个参数 (两个变量需要括号括起来)
Port app = (a,b) ->{ //实现区 };
示例以上代码已经有了;不同参数可在以上代码的基础上自行更变应用
# 静态内部类
静态内部类在前面加 static
即可,静态内部类只能调用静态的成员,用于调试
特点:
- 创建静态内部类实例无需创建外部类实例
- 静态内部类可定义 静态成员/实例成员
- 静态内部类可直接访问外部类静态成员,访问外部类成员则需外部类实例去访问
public class Outer {
static class Inner {
// 静态内部类
}
}
示例:
public class OuterStatic {
int a = 10;
static int b = 10;
static class Inner{
int c = 20;
static int d = 20 ;
// 访问外部
public void print() {
System.out.println("new OuterStatic().a : " + new OuterStatic().a);
// System.out.println(OuterStatic.this.a); (报红)
// System.out.println(a); (报红)
System.out.println("b : " + b);
System.out.println("OuterStatic.b : " + OuterStatic.b);
}
}
}
/* 运行结果
inner.a : 20
inner.b : 20
new OuterStatic().a : 10
b : 10
OuterStatic.b : 10
*/
# 内部类继承
内部类继承相对较复杂,需要设置专门的语法完成
继承内部类时,必须有构造方法带参数的,参数是内部类的外部类对象,同时构造方法里要借助外部对象进行实例内部类 ==外部类.super()==
public class OuterExtends {
class Inner {
private String name;
public Inner(String name) {
this.name = name;
}
public String info(){
return name;
}
}
}
class Demo extends OuterExtends.Inner {
public Demo(OuterExtends out,String name) {
out.super(name);
}
public static void main(String[] args) {
// 继承内部类进行调用
Demo demo = new Demo(new OuterExtends() , "柏竹");
System.out.println("输出内部类成员:"+demo.info());
}
}
/* 运行结果
输出内部类成员:柏竹
*/
# 代码块
# 局部代码块
局部代码块 是定义在指定的方法或作用域中
{}
范围的作用域,只需关注作用域
# 成员代码块
成员代码块 定义在 类中的 成员位置
- 优先执行与 构造方法,一般用于对 成员进行初始化的操作
- 每次实例对象都会执行一次
# 静态代码块
静态代码块 定义在 类中的 ==static{ }==
- 优先于 主方法的执行、构造方法的执行
- 只会执行一次,无论实例对象多次(一般用于初始化静态成员)
- 静态代码块类似于一个方法,但不可以存在于任何方法中
- 静态代码块可以置于类中的任何地方,类中可以有多个静态初始化块(存在多个静态也会依按顺序执行代码块)
# 代码块的加载顺序
类的加载顺序
- 父类 静态对象和静态代码块
- 子类 静态对象和静态代码块
- 父类 非静态对象和非静态代码块
- 父类 构造函数
- 子类 非静态对象和非静态代码块
- 子类 构造函数
public class Demo {
public static void main(String[] args) {
new B();
}
}
class A{
public A() {
System.out.println("A 父类 无参构造方法");
}
{
System.out.println("A 父类 不同初始化块");
}
static{
System.out.println("A 父类 静态初始化块");
}
}
class B extends A{
public B() {
System.out.println("B 子类 无参构造方法");
}
{
System.out.println("B 子类 不同初始化块");
}
static{
System.out.println("B 子类 静态初始化块");
}
}
/* 运行结果
A 父类 静态初始化块
B 子类 静态初始化块
A 父类 不同初始化块
A 父类 无参构造方法
B 子类 不同初始化块
B 子类 无参构造方法
*/