3.10 形式参数和返回值的深入研究
3.10.1 形式参数的深入研究
当形式参数是基本数据类型时,我们在前面已经学过了,现在研究的是形式参数是引用型数据类型(数组、类、抽象类接口)。
1、当形式参数为一个类时,需要传递的实际上是该类的一个对象。
class Student {
public void study() {
System.out.println("Good Good Study,Day Day Up");
}
}
class StudentDemo {
public void method(Student s) { //ss; ss = new Student(); Student s = new Student();
s.study();
}
}
class StudentTest {
public static void main(String[] args) {
//需求:我要测试Student类的study()方法
Student s = new Student();
s.study();
System.out.println("----------------");
//需求2:我要测试StudentDemo类中的method()方法
StudentDemo sd = new StudentDemo();
Student ss = new Student();
sd.method(ss);
System.out.println("----------------");
//匿名对象用法
new StudentDemo().method(new Student());
}
}
运行结果:
2、当形式参数为一个抽象类时,需要传递的实际上是该抽象子类的一个对象。
abstract class Person{
public abstract void study();
}
class PersonDemo{
public void method(Person p){
p.study();
}
}
//定义一个具体的学生类
class Student extends Person{
public void study() {
System.out.println("Good Good Study,Day Day Up");
}
}
class PersonTest{
public static void main(String[] args){
//目前是没有办法使用
//因为抽象类没有对应的具体类
//那么,我们就应该定义一个具体的类
//需求:我要使用PersonDemo类中的method()方法
PersonDemo pd = new PersonDemo();
//使用多态建立对象
Person p = new Student();
pd.method(p);
}
}
运行结果:
2、当形式参数为一个接口时,需要传递的实际上是该该接口的实现类的一个对象。
//定义一个爱的接口
interface Love{
//定义一个抽象方法
public abstract void love();
}
class LoveDemo{
public void method(Love l){
l.love();
}
}
//定义具体类实现接口
class Teacher implements Love{
public void love(){
System.out.println("老师爱学生");
}
}
class TeacherTest{
public static void main(String[] args){
//需求:我要测试LoveDemo类中love()方法
LoveDemo ld = new LoveDemo();
Love l = new Teacher();
ld.method(l);
}
}
运行结果:
3.10.2 返回值的深入研究
1、返回值类型是类时:其实返回的是该类的对象
class Student{
public void study(){
System.out.println("Good Good Study,Day Day Up");
}
}
class StudentDemo{
public Student getStudent(){
//Student s = new Student();
//return s;
//简化
return new Student();
}
}
class StudentTest2{
public static void main(String[] args){
//需求:我要使用Student类的study()方法
//但是这一次我的要求是,不要直接创建Student的对象。
//要让你使用StudentDemo帮你创建对象。
StudentDemo sd = new StudentDemo();
Student s = sd.getStudent();
s.study();
}
}
运行结果:
2、返回值类型是抽象类时:其实返回到是该抽象类的子类的对象
abstract class Person{
public abstract void study();
}
class PersonDemo{
public Person getPerson(){
//return new Person(); Person是抽象的,无法实例化
//Person p = new Student();
//return p;
return new Student();
}
}
class Student extends Person{
public void study(){
System.out.println("Good Good Study,Day Day Up");
}
}
class PersonTest2{
public static void main(String[] args){
//需求:我要测试Person类中的study()方法。
PersonDemo pd = new PersonDemo();
Person p = pd.getPerson();
p.study();
}
}
运行结果:
3、返回值类型是接口时:其实返回的是实现该接口的类的一个对象
interface Love{
//定义一个抽象方法
public abstract void love();
}
class LoveDemo{
public Love getLove(){
//Love l = new Teacher();
//return l;
return new Teacher();
}
}
//定义具体类实现接口
class Teacher implements Love{
public void love(){
System.out.println("老师爱学生");
}
}
class TeacherTest2{
public static void main(String[] args){
//测试
LoveDemo ld = new LoveDemo();
Love l = ld.getLove();
l.love();
}
}
运行结果:
3.10.3 链式编程
链式编程:每次调用完方法后,返回的是一个对象
class Student{
public void study(){
System.out.println("Good Good Study,Day Day Up");
}
}
class StudentDemo{
public Student getStudent(){
//Student s = new Student();
//return s;
//简化
return new Student();
}
}
class StudentTest3{
public static void main(String[] args){
//需求:我要使用Student类的study()方法
//但是这一次我的要求是,不要直接创建Student的对象。
//要让你使用StudentDemo帮你创建对象。
StudentDemo sd = new StudentDemo();
//Student s = sd.getStudent();
//s.study();
sd.getStudent().study();
}
}
运行结果:
3.11 包
3.11.1 包的定义及注意事项
1、定义:package 包名;多级包用“.”分开。例如,package cn.itcast;
package cn.itcast;
class HelloWorld{
public static void main(String[] args){
System.out.println("Hellow World");
}
}
注意事项:
1)、package语句必须是程序的第一条可执行的代码
2)、package语句在一个java文件中只能有一个
3)、如果没有package,默认表示无包名
3.11.2 带包的类的编译和运行
1、编译时:javac -d . HelloWorld.java,此时会在当前文件夹下成包名所代表的各个路径
2、运行时:java cn.itcast.HelloWorld
3.11.3 不同包下的类之间的访问
导包:
格式:import 包名;这种方式导入到的是包的名称。
/*
Demo类,求和
*/
package com.liuyi;
public class Demo {
public int sum(int a,int b) {
return a + b;
}
}
package cn.itcast;
import com.classmate.Demo;
class Test {
public static void main(String[] args) {
//Demo d = new Demo();
//com.classmate.Demo d = new com.classmate.Demo();
Demo d = new Demo();
System.out.println(d.sum(10,20));
}
}
3.11.4 面试题:package,import,class有没有顺序关系?
package > import > class。其中package只能有一个,import可以有多个,class可以有多个,建议用一个。
3.12 修饰符
修饰符有权限修饰符:private,默认,protected,public;状态修饰符:static,final;抽象修饰符:abstract
3.12.1 四种权限修饰符
3.12.2 各个权限符的使用范围
3.13 内部类
3.13.1 内部类的概述
将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类,嵌套类)。
3.13.2 内部类的访问规则
1、内部类可以直接访问外部类中的成员,包括私有。之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式: 外部类名.this。
2、外部类要访问内部类,必须建立内部类对象。
class Outer{
int x = 3;
//内部类Inner
class Inner{
int x = 4;
void function(){
int x = 6;
System.out.println("innner:"+ x);
System.out.println("innner:"+ this.x);
System.out.println("innner:"+ Outer.this.x);
}
}
void method(){
Inner in = new Inner();
in.function();
}
}
class InnerClassDemo{
public static void main(String [] args){
Outer out = new Outer();
out.method();
//直接访问内部类成员
//Outer.Inner in =new Outer().new Inner();
}
}
运行结果:
3.13.3 成员内部类
当内部类定义在外部类的成员位置上,可以在外部其他类中直接建立内部类对象。格式: 外部类名.内部类名 变量名 = 外部类对象.内部类对象。Outer.Inner in =new Outer().new Inner()
class Outer{
private int num = 10;
//成员位置
class Inner{
public void show(){
System.out.println(num);
}
}
}
class InnerClassDemo3{
public static void main(String[] args){
//需求:访问Inner类的show()方法。
//Inner i = new Inner();
//i.show();
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
运行结果:
内部类可以用静态修饰是因为内部类可以看成是外部类的成员,当内部类用静态修饰后,内部类里面可以有静态成员,也可以有非静态成员。在外部其他类中访问static内部类的非静态成员的格式为:new 外部类名.内部类名().方法名();例如:new Outer.Inner().function()。在外部其他类中,直接访问static内部类的静态成员格式为: 外部类名.内部类名.方法名();例如:Outer.Inner.function();
class Outer{
private int num = 10;
private static int num2 = 20;
//内部类可以用静态修饰是因为内部类可以看成是外部类的成员
public static class Inner{
public void show(){
System.out.println(num2);
}
public static void show2(){
System.out.println(num2);
}
}
}
class InnerClassDemo4 {
public static void main(String[] args) {
//使用内部类
//内部类被static修饰后访问的方式是这样的:
//格式:外表类名.内部类名 对象名 = new 外部类名.内部类名();
Outer.Inner oi = new Outer.Inner();
oi.show();
oi.show2();
//show2()是静态的,还有另一种访问方式:直接通过类名调用
Outer.Inner.show2();
}
}
运行结果:
3.13.4 局部内部类
当内部类定义在外部类的局部位置时,可以直接访问外部类中的成员,因为还持有外部类中的引用。不可以访问它所在的局部中非final变量。只能访问被final修饰的局部变量。
class Outer{
private int num = 10;
public void method(){
final int num2 = 20;//必须使用final修饰,否则编译不通过
class Inner{
public void show(){
System.out.println(num);
System.out.println(num2);
}
}
Inner i = new Inner();
i.show();
}
}
class InnerClassDemo5{
public static void main(String[] args){
Outer o = new Outer();
o.method();
}
}
运行结果:
思考:为什么局部内部类访问局部变量必须用final修饰呢?
因为局部变量会随着方法的调用完毕而消失,这个时候,局部对象并没有立马从堆内存中消失,还要使用那个变量。为了让数据还能继续被使用,就用fianl修饰,这样,在堆内存里面存储的其实是一个常量值。
3.13.5 匿名内部类
1、匿名内部类的介绍
1)匿名内部类其实就是内部类的简化写法。
2)定义匿名内部类的前提:存在一个类或者接口
3)格式:new 类名或者接口名(){
重写方法;
}
4)匿名内部类的本质是一个继承了该类或者实现了该接口的子类匿名对象。
interface Inter{
public abstract void show();
}
class Outer{
public void method(){
new Inter(){
public void show(){
System.out.println("show");
}
}.show();
}
}
class InnerClassDemo6{
public static void main(String[] args){
Outer o = new Outer();
o.method();
}
}
运行结果:
一个匿名内部类只能调用一个方法,类似一个匿名对象只能调用一个方法。当匿名内部类重写多个方法时,该如何调用方法呢?
可以用一个引用对象指向该匿名内部类,就可以多个调用方法了。
interface Inter{
public abstract void show();
public abstract void show2();
}
class Outer {
public void method() {
Inter i = new Inter() { //多态
public void show() {
System.out.println("show");
}
public void show2() {
System.out.println("show2");
}
};
i.show();
i.show2();
}
}
class InnerClassDemo6{
public static void main(String[] args){
Outer o = new Outer();
o.method();
}
}
运行结果:
2、匿名内部类在开发中的应用(Android开发中用的很多)
看下面的代码,用匿名对象来实现。
interface Person {
public abstract void study();
}
class PersonDemo {
//接口名作为形式参数
//其实这里需要的不是接口,而是该接口的实现类的对象
public void method(Person p) {
p.study();
}
}
//实现类
class Student implements Person {
public void study() {
System.out.println("好好学习,天天向上");
}
}
class InnerClassTest2{
public static void main(String[] args){
PersonDemo pd = new PersonDemo();
Person p = new Student();
pd.method(p);
}
}
运行结果:
在Android开发中,因为手机内存不大,所以内存很紧张,匿名内部类的特点就是使用后就会从堆内存中消失。
interface Person {
public abstract void study();
}
class PersonDemo {
//接口名作为形式参数
//其实这里需要的不是接口,而是该接口的实现类的对象
public void method(Person p) {
p.study();
}
}
class InnerClassTest2{
public static void main(String[] args){
PersonDemo pd = new PersonDemo();
//匿名内部类在开发中的使用
pd.method(new Person(){
public void study(){
System.out.println("好好学习,天天向上");
}
});
}
}
运行结果;