Java方法
- 何为方法
- 方法是解决一类问题的步骤的有序组合 eg System.out.println() 类+对象+方法
- 方法包含与类或对象中
- 方法在程序中被创建,在其他地方被引用
设计方法时最好一个方法完成一个功能
输出1到1000 能被5整除的数的代码
- 方法定义及调用
修饰符 返回值类型 方法名(参数类型 参数名){
...
方法体
...
return 返回值;
}
调用方法:对象名.方法名(实参)
方法包含一个方法头和一个方法体,方法的所有部分有
修饰符:告诉编译器如何调用该方法,定义了该方法的访问类型
返回值类型:方法可能会返回值,return ValueType是方法返回值的数据类型,有些方法执行所需操作但无返回值,return ValueType是关键字void
return 0; //有终止方法的作用
方法名:方法的实际名字,方法名和参数表共同构成方法签名
参数类型:1.形参:在调用时接受外界输入的数据2.实参:调用方法时实际传给方法的数据
方法体:方法体包含具体语句,定义该方法的功能
- 方法重载
重载规则:1.方法名必须相同 2.参数列表中的个数或类型、参数排列顺序不同 3.方法的返回类型可以相同可以不同 4.仅仅返回类型不同不足以成为方法的重载
- 命令行传参
- 可变参数
1.Java支持传递同类型的可变参数给一个方法 2.在方法声明中,在指定参数类型后加一个省略号(…) 3.一个方法中只能指定一个可变参数,它必须是方法的最后一个参数,如何普通的参数必须在它之前声明
eg:
public class kebiancanshu {
public static void main(String args[]) {
//调用可变参数的方法
printMax(54, 8, 4, 6.0);
printMax(new double[]{1, 2, 3});
}
public static void printMax(double... numbers) {
if (numbers.length ==0) {
System.out.println("No argument passed");
return;
}
double result = numbers[0];
//排序
for (int i = 1; i < numbers.length; i++) {
if (numbers[i] > result) {
result = numbers[i];
}
System.out.println("The max value is" + result);
}
}
}
- 递归
1.递归就是A方法调用A方法
2.作用:把大型复杂问题层层转化为与原问题相似的规模较小的问题求解,用有限的语句来定义对象的无限集合
递归结构包括两部分:1.递归头:什么时候不调用自身方法,如果没有头,将陷入死循环 2.递归体:什么时候需要调用自身方法
public class digui {
public static void main(String[] args) {
System.out.println(f(5));
}
public static int f(int n){
if(n==1){
return 1;
}else{
return n*f(n-1);
}
}
}
利用递归求得了5的阶乘为120
Java数组
-
数组概述
定义:
1.数组是相同类型数据的有序集合 2.数组描述的是相同类型的若干个数据,按照一定先后次序排列组合而成 3.其中的每一个数据称为一个数组元素,每个数组元素可以通过下标访问
基本特点:
1.长度确定,数组创建后大小不可修改 2.其元素类型必须相同 3.数组中的元素可以是任数据类型,包括基本类型和引用类型 4.数组变量属引用类型,数组可以看成对象,数组中每个元素相当于该对象的成员变量,数组本身就是变量,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的
数组边界:
下标的合法区间:[0,length-1] ,数组下标越界异常
-
数组声明创建
声明数组变量的语法:
dataType[] arrayrefVar; //首选方法
或
dataType arrayRefVar[];
Java语言使用new操作符来创建数组,语法如下:
dataType[] arrayRefVar = new dataType[arraySize];
1. 数组的元素是通过索引访问的,数组索引从0开始 2.获取数组长度: arrays.length
代码示例:
public class shuzu {
//数组的类型 数组的名字 = 数组的值
public static void main(String[] args) {
int[] nums; // 声明一个数组
nums=new int[10]; //创建一个数组
nums[0]=1; //声明和创建数组可以一起写:int[] nums=new int [10];
nums[1]=2;
nums[2]=3;
nums[3]=4;
nums[4]=5;
nums[5]=6;
nums[6]=7;
nums[7]=8;
nums[8]=9;
nums[9]=10;
//计算所有元素的和
int sum=0;
//获取数组长度
for(int i=0;i< nums.length;i++){
sum=sum+nums[i];
}
System.out.println("总和为:"+sum);
}
}
上面代码的声明和创建可以写为: int[] nums = new int [10];
数组声明时候并不存在,只有创建的时候存在
数组的三种初始化方式:
1.静态初始化(创建+赋值)
int [] a= {1,2,3}; //基本类型
Man[] mans = {new Man(1,1),new Ma(2,2)}; //引用类型
2.动态初始化(包含了默认初始化)
int[] a = new int[2];
a[0]=1;
a[2]=2;
3.默认初始化
数组是引用类型,它的元素相当于类的实例变量,当数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化
-
数组使用
代码展示(普通for循环):
public class p55shuzu {
public static void main(String[] args) {
int[] arrays={1,2,3,4,5};
//打印全部的数组元素
for (int i=0;i<arrays.length;i++){
System.out.println(arrays[i]);
}
System.out.println("-------------");
//计算所有元素的和
int sum=0;
for (int i=0;i<arrays.length;i++){
sum=sum+arrays[i];
}
System.out.println("sum="+sum);
System.out.println("--------------");
//查找最大元素
int max=arrays[0];
for (int i=1;i<arrays.length;i++){
if (arrays[i]>max){
max=arrays[i];
}
}
System.out.println("max:"+max);
}
}
1.for-Each循环
public class shuzu_forEach {
public static void main(String[] args) {
int[] arrays={1,2,3,4,5};
//JDK1.5,无下标
for (int array:arrays) {
System.out.println(array);
}
}
}
2.数组作方法入参
3.数组作返回值
-
多维数组
1.多维数组可以看成数组的数组,比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组
2.二维数组的定义
//二维数组a是一个2行5列的数组
int a[ ][ ] = new int[2][5];
示例代码:
public class erweishuzu {
public static void main(String[] args) {
//[4][2]
/*
1,2 array[0]
2,3 array[1]
3,4 array[2]
4,5 array[3]
*/
int [][] array={{1,2},{2,3},{3,4},{4,5}};
for (int i = 0; i < array.length ; i++) {
for (int j = 0; j < array[i].length ; j++) {
System.out.println(array[i][j]);
}
}
}
//打印数组元素
public static void printArray(int[] arrays) {
for (int i = 0; i < arrays.length; i++) {
System.out.println(arrays[i] + " ");
}
}
}
-
Arrays类
1.数组的工具类java.util.Array 2.API中提供了一个工具类Arrays供我们使用,从而可以对数据对象进行基本操作 3.查看JDK帮助文档 4.Arrays类中的方法都是static修饰的静态方法,使用时可直接用类名进行调用,而“不用”使用对象来调用(不用不是不能)
Arrays类具有以下常用功能:
1.给数组赋值:通过fill方法 2.对数组排序:通过sort方法(按升序) 3.比较数组:通过equals方法比较数组元素值是否相同 4.查找数组元素:通过binarySearch方法对排序好的数组进行二分查找法操作
代码示例:
import java.util.Arrays;
public class Arraysyingyong {
public static void main(String[] args) {
int[]a = {1,28,7,95,452,8795};
// System.out.println(a); //[I@2d98a335
//打印数组元素Arrays.tostring
// System.out.println(Arrays.toString(a));
Arrays.sort(a); //数组进行排序
System.out.println(Arrays.toString(a));
}
}
-
稀疏数组
1.当一个数组中大部分元素为0,或者为同一值时,可以用稀疏数组来保存该数组 2.稀疏数组的处理方式为记录数组一共有几行几列有多少个不同值,把具有不同值的元素和行列记在一个小规模的数组中
代码示例:
public static void main(String[] args) {
//创建一个11*11的数组 0:没有棋子 1:黑子 2:白子
int[][] array1 = new int[11][11];
array1[1][2] = 1;
array1[2][3] = 1;
//输出原始的数组
System.out.println("=====原始数组=====");
for (int[] ints : array1) {
for (int anInt : ints) {
System.out.print(anInt+" ");
}
System.out.println();
}
//转换为稀疏数组存储
System.out.println("=====稀疏数组=====");
//1. 获取有效值的个数
int sum = 0;
for (int i = 0; i < array1.length; i++) {
for (int j = 0; j < array1[i].length; j++) {
if(array1[i][j]!=0)
sum++;
}
}
System.out.println("有效值个数为" + sum);
//2.创建一个稀疏矩阵
int[][] array2 = new int[sum+1][3];
array2[0][0] = 11;
array2[0][1] = 11;
array2[0][2] = sum;
//3. 遍历二维数组,将非零的值存放在稀疏数组中。
int count = 0;
for (int i = 0; i < array1.length; i++) {
for (int j = 0; j < array1[i].length; j++) {
if(array1[i][j]!=0)
{
count++;
array2[count][0] = i;
array2[count][1] = j;
array2[count][2] = array1[i][j];
}
}
}
//输出稀疏矩阵
for (int i = 0; i < array2.length; i++) {
System.out.println(array2[i][0]+" "+array2[i][1]+" "+array2[i][2]);
}
//转化为原始数组
System.out.println("=====还原数组=====");
//1.读取稀疏数组
int[][] array3 = new int[array2[0][0]][array2[0][1]];
//2.给其中的元素还原它的值
for (int i = 1; i < array2.length; i++) {
array3[array2[i][0]][array2[i][1]] = array2[i][2];
}
//输出还原的数组
for (int[] ints : array3) {
for (int anInt : ints) {
System.out.print(anInt+" ");
}
System.out.println();
}
}
冒泡排序
- 两层循环,外层冒泡轮数,里层依次比较
代码示例:
//冒泡排序(时间复杂度为O(n²))
//1.比较数组中两个相邻的元素,如果第一个数比第二个数大,我们就交换他们的位置
//2.每一轮比较,都至少会产生出一个最大,或者最小的数字;
//3.下一轮则可以少一次比较!
//4.依次循环,直到结束!
public static int[] sort(int[] nums){
//轮数,五个数依次确定四个最小值即可,所以四轮即可
boolean flag = true; //当某一轮比较没有发生改变,即已经有序,则可以直接返回
for (int i = 0; i < nums.length - 1; i++) {
//从前往后依次顺序相邻比较,第i轮已经确定i个最大值
flag = false;
for (int j = 0; j < nums.length - 1 - i; j++) {
if (nums[j] > nums[j+1]) {
int temp = nums[j+1];
nums[j + 1] = nums[j];
nums[j] = temp;
}
}
if(flag)
{
return nums;
}
}
return nums;
}
Java面向对象编程
-
初识面向对象
- 步骤清晰简单,第一步做什么,第二步做什么,适合处理一些简单问题
有分类的思维模式,思考问题首先会解决问题需要哪些分类,最后对分类下的细节进行面向过程的思索
- 面向对象适合处理复制的问题,适合处理需要多人协作的问题
- 对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作仍然需要面向对象的思路处理
- 面向对象编程的本质:以类的方式组织代码,以对象的组织(封装)数据
- 三大特性:封装、继承、多态
-
类与对象的创建
- 类是一种抽象的数据类型,它是某一类事物整体描述,但不能代表某一个具体的事物
- 对象是抽象概念的具体实例
- 创建和初始化对象
- 使用new关键字创建对象,用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用。
- 类中的构造器也称为构造方法,是在进行创建对象的时候必须调用的。并且构造器有以下两个特点:
必须和类的名字相同
必须没有返回类型,也不能写void
示例代码:
//类的定义
//Person类
public class Person {
//属性: 字段
String name;//默认null
int age;//默认0
//构造器
Person(){
}
Person(String name,int age){
this.name = name;
this.age = age;
}
//方法
public void study(){
System.out.println(this.name + "在学习");
}
}
//一个测试类
//一个项目应该只存在一个main方法
public class Application {
public static void main(String[] args) {
//类:抽象的,实例化
//类实例化后会返回一个自己的对象!
//xiaohong对象就是一个Student类的具体实例!
Person xiaohong = new Person();
Person xiaoming = new Person("xiaoming",3);
System.out.println(xiaohong.name);//null
System.out.println(xiaohong.age);//null
xiaohong.name = "xiaohong";
xiaohong.age = 18;
System.out.println(xiaohong.name);//xiaohong
System.out.println(xiaohong.age);//18
xiaoming.study();//调用方法
}
}
- 构造器
- 和类名相同
- 没有返回值
- 作用:new本质在调用构造方法;初始化对象的值
- 注意点:定义有参构造后,如果想使用无参构造,显示的定义一个无参的构造
- 代码示例
//Person类
public class Person {
//属性: 字段
String name;//默认null
int age;
//构造器
//一个类即时什么也没写,它也会存在一个隐式的构造器方法(无参,默认值)
//增加构造器的快捷键Alt+insert
//无参构造器,如果一个构造器都没有,这就是隐式的构造器方法
Person(){
}
//有参构造器:一旦定义了有参构造,再要使用无参构造就得显式定义
Person(String name, int age){
this.name = name;
this.age = age;
}
}
//一个项目应该只存在一个main方法
public class Application {
public static void main(String[] args) {
//类:抽象的,实例化
//类实例化后会返回一个自己的对象!
//xiaohong对象就是一个Student类的具体实例!
Person xiaohong = new Person();
Person xiaoming = new Person("xiaoming",3);
System.out.println(xiaoming.name);//xiaoming
System.out.println(xiaoming.age);//3
}
}
面向对象的三大特征
1.封装
定义:类的内部数据操作细节自己完成,不许外部干涉,仅暴露少量方法给外部使用
优点:1.提高程序安全性,保护数据 2.隐藏代码的实现细节 3.统一接口 4.系统的可维护性增加
代码示例:
//类 private:私有
public class Student {
//属性私有
private String name;//名字
private int id;//学号
private char sex;//性别
private int age;//年龄
//提供一些可以操作这个属性的方法
//提供一些public的get、set方法
//get 获得这个数据
public String getName() {
return name;
}
//set 设置这个数据
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age<0||age>120){//不合法的输入
this.age = 3;
}else{
this.age = age;
}
}
}
2.继承
继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模
extends的意思是“扩展”,子类是父类的扩展
JAVA中类只有单继承,一个儿子只能有一个爸爸,但一个爸爸可以有多个儿子
继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等
继承关系的俩个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。
子类和父类之间,从意义上讲应该具有"is a"的关系
object类
- super
注意点:1.super调用父类的构造方法,必须在构造方法的第一个 2.super 必须只能出现在子类的方法或者构造方法中 3.super和 this不能同时调用构造方法(因为super();和this();都必须在第一行)
与this的不同点:1代表的对象不同(this:本身调用者这个对象; super:代表父类对象的) 2.应用前提的不同(this:没有继承也可以使用; super:只能在继承条件才可以使用) 3构造方法的不同(this();本类的构造; super():父类的构造)
方法重写
final修饰的类不能被继承
代码示例:
//父类
public class Person {
protected String name = "father";
Person(){
System.out.println("Person无参构造执行了");
}
public void print(){
System.out.println("Person");
}
private void printPrivate(){
System.out.println("PersonPrivate");
}
}
// Student: 派生类,子类
public class Student extends Person {
private String name = "son";
Student(){
//隐藏代码,如果未显式调用父类构造器,默认调用父类无参构造
super();//调用父类构造器或子类的其他构造器,必须在构造器的第一行
System.out.println("Student无参构造执行了");
}
Student(String name){
this();
this.name = name;
}
public void print(){
System.out.println("Student");
}
public void testPrint(){
print();
this.print();
super.print();
//super.printPrivate();//父类私有方法无法访问
}
public void testName(String name){
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
}
}
//执行类
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.testName("name");
student.testPrint();
}
}
方法重写
前提:需要有继承关系,子类重写父类的方法
特点:1.方法名必须相同 2.参数列表列表必须相同 3.修饰符:范围可以扩大但不能缩小(Public>Protected>Default>Private ) 4.抛出的异常:范围,可以被缩小,但不能扩大(Exception(大) -->ClassNotFoundException)
快捷键:Alt+Insert; override
不能重写的方法:static 方法,属于类,不属于实例 final 常量 private方法
代码示例:
//父类
public class B {
public static void test(){
System.out.println("B->test()");
}
public void test1(){
System.out.println("B->test1()");
}
}
//子类
//重写都是方法的重写,和属性无关
public class A extends B{
public static void test(){
System.out.println("A->test()");
}
//override:重写
@Override //注解:有功能的注释
public void test1() {
System.out.println("A->test1()");
}
}
//执行类
public class Application {
//静态方法和非静态方法区别很大
public static void main(String[] args) {
//静态方法:方法的调用只和左边有关,即定义的数据类型
A a = new A();
a.test();//A
//父类的引用指向A
B b = new A();
b.test();//B
//非静态方法:子类重写了父类的方法
a.test1();//A
b.test1();//A
}
}
-
多态
- 即同一方法可以根据发送对象的不同而采用多种不同的行为方式。
- 一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多
- 多态存在的条件(有继承关系; 子类重写父类方法父类; 引用指向子类对象)
-
多态注意事项:
(1)多态是方法的多态,属性没有多态 (2)父类和子类,有联系,不然会报错类型转换异常! CLassCastException ! (3)存在条件:继承关系,方法需要重写,父类引用指向子类对象 - instanceof (类型转换) 引用类型,判断一个对象是什么类型
代码示例:
public class Application {
public static void main(String[] args) {
//Object > String
//Object > Person > Student
//Object > Person > Teacher
Object object = new Student();
System.out.println(object instanceof Student);//true
System.out.println(object instanceof Person);//true
System.out.println(object instanceof Object);//true
System.out.println(object instanceof Teacher);//true
System.out.println(object instanceof String);//false
System.out.println("======================");
Person person = new Student();
System.out.println(person instanceof Student);//true
System.out.println(person instanceof Person);//true
System.out.println(person instanceof Object);//true
System.out.println(person instanceof Teacher);//false
//System.out.println(person instanceof String);//编译报错
System.out.println("======================");
Student student = new Student();
System.out.println(student instanceof Student);//true
System.out.println(student instanceof Person);//true
System.out.println(student instanceof Object);//true
//System.out.println(student instanceof Teacher);//编译报错
//System.out.println(person instanceof String);//编译报错
System.out.println("======================");
/*
编译能否通过看左边。运行结果看右边
*/
}
}
-
抽象类
- abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,那么该类就是抽象类
- 抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类
- 抽象类,不能通过使用new关键字来创建对象,它是用来让子类继承的
- 抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的
- 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类
代码示例:
//abstract 抽象类
//类只能单继承,但是接口可以多继承
public abstract class Action {
//约束~ 有人帮我们实现~
//abstract ,抽象方法,只有方法名字,没有方法的实现
public abstract void doSomething();
public void hello(){
}
public Action() {
System.out.println("抽象类构造器");
}
/*
特点:
1. 不能new这个抽象类,只能靠子类去实现它;约束
2. 抽象类中可以写普通方法
3. 抽象方法必须在抽象类中
抽象的抽象
思考题:
1. 不能new?存在构造器吗 存在
2. 抽象类的意义 提高开发效率
*/
}
//抽象类的所有方法,继承了它的子类,都必须要实现它的方法。除非子类也是抽象类
public class A extends Action{
public A() {
System.out.println("子类构造器");
}
@Override
public void doSomething() {
}
}
public class Application {
public static void main(String[] args) {
A a = new A();
}
}
运行结果: 抽象类构造器
子类构造器
-
接口
-
普通类:只有具体实现
- 抽象类:具体实现和规范(抽象方法)都有
- 接口:只有规范!自己无法写方法~专业的约束!约束和实现分离:面向接口编程
- 接口就是规范,定义的是一组规则,体现了现实世界中”如果你是…则必须能…”的思想。如果你是天使,则必须能飞 eg:如果你是汽车,则必须能跑
- 接口的本质是契约,就像我们人间的法律一样,制定好后大家都遵守
- 面向对象的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如c++、java、c等),就是因为设计模式所研究的,实际上就是如何合理的去抽象
- 声明类的关键字是class,声明接口的关键字是interface
- 作用:(1)约束; 定义一些方法,让不同的人实现; (2) public abstract; (3) (4)public static final; (5) 接口不能被实例化,接口中没有构造方法; (6)implements可以实现多个接口 (7)必须要重写接口中的方法
代码示例
//接口1
public interface UserService {
//接口中的所有成员都是常量 public static final
public static final int age = 99;
String name = "name";
//接口中的所有定义其实都是抽象 public abstract
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
void timer();
}
//接口2
public interface TimeService {
int age = 2;
void timer();
}
//抽象类 : extends 单继承
//类 可以实现接口 implements接口
//实现接口的类,就需要重写接口中的方法
//利用接口实现伪多继承
//实现类
public class UserServiceImpl implements UserService,TimeService{
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void query(String name) {
}
@Override
public void timer() {
System.out.println("timer");
System.out.println(TimeService.age);
System.out.println(UserService.age);
//System.out.println(age);//编译报错
System.out.println(name);
}
}
//测试类
public class App{
public static void main(String[] args) {
TimeService time = new UserServiceImpl();
time.timer();
UserService user = new UserServiceImpl();
user.timer();
}
}
-
内部类
内部类就是在一个类的内部在定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类了
// 外部类
class Outer{
// 内部类
class Inner{
// 也会生成class文件
}
}
- 成员内部类
(1)在类的内部定义,与实例变量、实例方法同级别的类 (2)外部类的一个实例部分,创建内部类对象时,必须依赖外部类对象 (3)当外部类、内部类存在重名属性时,会优先访问内部类属性 (4)成员内部类里不能定义静态成员(static)、可以包含静态常量(static final)
public class Outer {
//实例变量
private String name = "张三";
private int age = 20;
//内部类
class Inner{
private String address = "北京";
private String phone = "110";
private String name = "李四";
//private static String country = ""; 不能包含静态成员
private static final String country1 ="中国";//但是能包含静态常量
//方法
public void show(){
//打印外部类属性 此时有重名属性name
System.out.println(Outer.this.name);// 张三
System.out.println(age);
//打印内部类中的属性
System.out.println(name);//李四
System.out.println(this.name);// 李四
System.out.println(address);
System.out.println(phone);
}
}
}
public class Test {
public static void main(String[] args) {
// 创建外部类对象
Outer outer = new Outer();
// 创建内部类对象
Outer.Inner inner1 = outer.new Inner();
inner1.show();
//一步到位
Outer.Inner inner2 = new Outer().new Inner();
inner2.show();
}
}
2.静态内部类
不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员
// 外部类
public class Outer{
//实例变量
private String name = "xxx";
private int age = 20;
// 静态内部类,级别和外部类相同
static class Inner{
private String address = "上海";
private String phone = "111";
// 静态成员
private static int count = 1000;
//方法
public void show(){
// 调用外部类的属性
// 1. 先创建外部类对象
Outer outer = new Outer();
// 2. 调用外部类对象的属性
System.out.println(outer.name);
System.out.println(outer.age);
// 调用静态内部类的属性和方法
System.out.println(address);
System.out.println(phone);
// 调用静态内部类的静态属性
System.out.println(count);
System.out.println(Inner.count);
}
}
}
// 测试类
public class Test{
public static void main(String[] args){
// 直接创建静态内部类对象
Outer.Inner inner = new Outer.Inner();
inner.show();
Inner inner1 = new Inner();
}
}
3.局部内部类
(1)定义在外部类方法中,作用范围和创建对象范围仅限于当前方法
(2)局部内部类访问外部类当前方法中的局部变量时,因无法保障变量的生命周期与自身相同,变量必须修饰为final
(3)限制类的使用范围,只能在当前方法中使用
// 外部类
public class Outer{
//实例变量
private String name = "刘德华";
private int age = 35;
//方法
public void show(){
// 定义局部变量
String address = "sz";
// 局部内部类:注意不能加任何访问修饰符
class Inner{
private String phone = "11234";
private String email = "ldh@qq.com";
//private static String country = ""; 不能包含静态成员
private static final String country1 ="中国";//但是能包含静态常量
public void show2(){
// 访问外部类的属性
System.out.println(name); // 相当于 Outer.this.name
System.out.println(age);
// 访问内部类的属性
System.out.println(this.phone);
System.out.println(this.email);
// 访问局部变量 jdk1.7要求必须常量final、jdk1.8自动添加final
System.out.println(address);
}
}
// 创建局部内部类对象
Inner inner = new Inner();
inner.show2();
//address = "123"; 因为局部内部类访问了address,所以address默认为final常量,后面不能进行更改
}
}
// 测试类
public class Test{
public static void main(String[] args){
// 创建外部类对象
Outer outer = new Outer();
outer.show();
}
}
4.匿名内部类
(1)没有类名的局部内部类(一切特征都与局部内部类相同)
(2)必须继承一个父类或者实现一个接口
(3)定义类、实现类、创建对象的语法合并,只能创建一个该类的对象
(4)优点:减少代码量
(5)缺点:可读性较差
//接口
public interface Usb {
public void service();
}
//测试类
public class Test {
public static void main(String[] args) {
// 使用匿名内部类优化(相当于创建了一个局部内部类)
Usb usb = new Usb(){ // Usb为一个接口
@Override
public void service(){
System.out.println("连接电脑成功,开始工作");
}
};
usb.service();
}
}