一个Java文件中定义多个类
-
只能有一个public类
-
其它的非public类只能默认修饰符,可以有多个非public类
-
在public类里是可以访问非public的类(因为在同一个包下)
package com.hqyj;
//一个源文件中只能有一个public类,类名跟文件名相同
public class A {
public static void main(String[] args) {
B b = new B();
b.btest();
}
}
//一个源文件中还可以有其它的非public(只能是默认修饰符)的类
class B{
public void btest(){
System.out.println("B类的方法");
}
}
class D{
}
内部类
定义在类中的类称为内部类
作用是封装,一般自己使用的类定义为内部类,不让别的类知道或使用这个内部类
成员内部类(内部类定义在大括号里)
-
内部类定义为一个成员(跟成员变量或方法同一级)
-
内部类可以用任意访问修饰符(一般起封装作用的话用private)
-
内部类可以访问外部类的属性或方法;外部类不能直接访问内部类的属性或方法,只能通过对象去访问
-
内部类的初始化要借助外部类的对象:Outer.Inner inner = outer.new Inner();
package com.hqyj;
public class Outer {
private String id = "abcd123";
private void funOuter(){
System.out.println("外部类的方法funOuter");
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.funOuter();
Outer.Inner inner = outer.new Inner();
inner.funInner();
System.out.println(inner.name);
}
private class Inner{
public Inner() {
System.out.println("Inner的构造方法");
}
private String name = "innerclass";
private void funInner(){
System.out.println(id);
System.out.println("内部类的方法funInner");
funOuter();
}
}
}
静态成员内部类
- 如果成员内部类是静态的,创建内部对象的方式: Inner inner = new OuterStatic.Inner();
- 内部类中只能访问外部类的静态属性和方法
- 在外部类中可以通过内部类的类名直接访问内部类的静态属性和方法
package com.hqyj;
public class OuterStatic {
private String nameOuter = "外部类的属性";
private static String nameOuterStatic = "外部类的静态属性";
private void funOuter(){
System.out.println("外部类的方法");
// System.out.println(nameInner);//不能访问内部类的属性
//funInner(); //不能访问内部类的方法
}
private static void funStaticOuter(){
System.out.println("外部类的静态方法");
System.out.println(Inner.nameStaticInner);
Inner.funStaticInner();
}
private static class Inner{
private String nameInner = "内部类的属性";
private static String nameStaticInner = "内部类的静态属性";
private void funInner(){
System.out.println("内部类的方法");
System.out.println(nameOuterStatic);
funStaticOuter();
}
private static void funStaticInner(){
System.out.println("内部类的静态方法");
System.out.println(nameOuterStatic);
funStaticOuter();
}
}
public static void main(String[] args) {
OuterStatic outer = new OuterStatic();
outer.funOuter();
Inner inner = new OuterStatic.Inner();
inner.funInner();
System.out.println(Inner.nameStaticInner);
OuterStatic.Inner.funStaticInner();
}
}
局部内部类(定义在方法中)
- 内部类定义在方法中
- 内部类的对象创建只能在这个方法中,创建内部类的方式:Inner inner = new Inner();
- 内部类可以访问外部类的属性和方法; 外部类不可以直接访问内部类的属性和方法,但是可以通过内部类的对象去访问
package com.hqyj;
public class OuterLocal {
private String nameOuter = "外部类的属性";
private void fun2Outer(){
}
private void funOuter(){
System.out.println("外部类的方法");
class Inner{
private String nameInner = "内部类的属性";
private void funInner(){
System.out.println("内部类的方法");
//内部类可以访问外部类的属性
System.out.println(nameOuter);
//内部类可以访问外部类的方法
fun2Outer();
}
}
// System.out.println(nameInner); //外部类不能直接访问内部类的属性
// funInner(); //外部类不能直接访问内部类的方法
Inner inner = new Inner();
inner.funInner();
System.out.println(inner.nameInner);
}
public static void main(String[] args) {
OuterLocal outer = new OuterLocal();
outer.funOuter();
}
}
匿名内部类
类只用一次,所以没有类名
一般用在接口作为方法的参数的情况
- Usb接口
package com.hqyj;
public interface Usb {
void work();
}
- Computer类
有一个方法的参数是Usb接口类型
package com.hqyj;
public class Computer {
//方法的参数是一个接口
public void useUsb(Usb usb){
usb.work();
}
}
- 调用接口参数的方法时,直接实现接口
这个接口的实现类没有名字,所以叫匿名类, 其它地方不可能用到它
package com.hqyj;
public class ComputerTest {
public static void main(String[] args) {
Computer computer = new Computer();
computer.useUsb(new Usb() {
@Override
public void work() {
System.out.println("鼠标正在工作...");
}
});
}
}
枚举 Enum
- 枚举定义
package com.hqyj;
public enum Season {
SPRING, SUMMER, AUTUMN, WINTER
}
- 枚举的使用
package com.hqyj;
public class SeasonTest {
public static void main(String[] args) {
Season spring = Season.AUTUMN;
switch (spring){
case SPRING:
System.out.println("春天播种");
break;
case SUMMER:
System.out.println("夏天施肥");
break;
case AUTUMN:
System.out.println("秋天收获");
break;
case WINTER:
System.out.println("收藏种子");
break;
}
}
}
类的方法
方法就是类的行为,通过方法执行一段代码,完成特定的功能
方法的定义:
[public] [static] [abstract] [fianl] 返回类型 方法名(类型 参数名, 类型 参数名){
//方法体代码
}
方法的特性:
-
除构造方法外,所有的方法都有返回类型,如果不需要返回值,返回类型是void
-
如果有返回值,方法必须有return语句(保证每一个分支都有return 语句),return语句后不能再有其它代码
-
方法可以无参数,有参数,还可以是不定长的参数
-
可变长参数放在方法参数的最后一个, 类型后面加3个点, 可变长参数在方法中当数组处理
-
方法同名,参数不同,就构成重载。可变长参数方法和固定长度参数的方法同时存在,优先调用定长参数的方法
public void fun1(){
System.out.println("没有返回值,返回类型是void");
}
//有返回类型,方法体必须有return语句,返回的内容必须跟返回类型一致
// 保证每一个分支都有返回语句
public String getName(){
String name = "";
if( 3 > 2){
name = "姓名";
}else {
}
return name;
/*
if( 3 > 2){
return "姓名";
}else {
return "";
}*/
}
//固定个数参数
public int sum(int a, int b){
System.out.println("a,b");
return a + b;
}
//类型后面有三个点参数叫可变长参数
// 可变长的参数只能是方法的最后一个参数
// 可变参数可以当数组处理
public int sum(int a, int... b){
System.out.println("a, b...");
int sum = 0;
sum += a;
for (int tmp : b) {
sum += tmp;
}
return sum;
}
public static void main(String[] args) {
MethodDemo methodDemo = new MethodDemo();
System.out.println(methodDemo.sum(1, 2, 3, 4, 5, 6));
}
传值调用和传引用调用
形参:形式参数,定义方法时给出参数名
//a, b就叫形参
public int sum(int a, int b){
}
实参:实际参数,调用方法时传的变量
int m = 3, n = 2;
//m,n 就叫实参
sum(m, n);
- 传值调用
当参数类型为基本类型时,在方法里面改变形参的值,不影响实参(理解为调用方法时copy了一份参数)
//定义方法
public int sum(int a, int b){
int sum = a + b;
a++;
b--;
return sum;
}
//调用方法
int x = 10;
int y = 20;
int sum = methodDemo.sum(x, y);
System.out.println(sum);
System.out.println("x:" + x + ", y:" + y); //x:10, y:20
- 传引用调用
当参数类型为引用类型(类,接口,数组),在方法里面改变这个对象的值,实参的对象的值也跟着改变(因为它们指向的是堆中的同一个对象实例)
Student实体类
package com.hqyj;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试类
package com.hqyj;
public class StudentTest {
public static void main(String[] args) {
StudentTest test = new StudentTest();
Student student = new Student("张三", 22);
test.updateStudent(student);
System.out.println(student);
}
public void updateStudent(Student stu){
stu.setAge(25);
}
}
方法的递归调用
方法里面调用自己,替代循环代码
(理解递归调用,知道方法被调用会在栈里压入一个方法帧,直到最后一次调用方法结束,再依次出栈,返回)
// 求1~n的和的递归方法
public int sumone2n(int n){
if(n == 1){
return 1;
}else {
return n + sumone2n(n - 1);
}
}
// 求n的阶乘的递归方法
public int factorial(int n){
if(n == 0){
return 1;
}else{
return n * factorial(n - 1);
}
}
// 斐波那契数列用递归
public long fibonacci(int n){
if(n == 1 || n == 2){
return 1;
}else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}