一、Java内部类
1、内部类
在Java中,也可以嵌套类(类中的类)。嵌套类的目的是将属于同一类的类分组,这使代码更具可读性和可维护性。
要访问内部类,请创建外部类的对象,然后创建内部类的对象:
class OuterClass {
int x = 10;
class InnerClass {
int y = 5;
}
}
public class MyMainClass {
public static void main(String[] args) {
OuterClass myOuter = new OuterClass();
OuterClass.InnerClass myInner = myOuter.new InnerClass();
System.out.println(myInner.y + myOuter.x);
}
}
// 输出 15 (5 + 10)
2、私有的内部类
与"常规"类不同,内部类可以是private 私有的或 protected受保护的。 如果不希望外部对象访问内部类,请将该类声明为private:
class OuterClass {
int x = 10;
private class InnerClass {
int y = 5;
}
}
public class MyMainClass {
public static void main(String[] args) {
OuterClass myOuter = new OuterClass();
OuterClass.InnerClass myInner = myOuter.new InnerClass();
System.out.println(myInner.y + myOuter.x);
}
}
3、Static 内部类
内部类也可以是static静态的,这意味着您可以在不创建外部类的对象的情况下访问它:
与 static静态属性和方法一样,static静态内部类无权访问外部类的成员。
class OuterClass {
int x = 10;
static class InnerClass {
int y = 5;
}
}
public class MyMainClass {
public static void main(String[] args) {
OuterClass.InnerClass myInner = new OuterClass.InnerClass();
System.out.println(myInner.y);
}
}
// 输出 5
4、从内部类访问外部类
内部类的一个优点是,它们可以访问外部类的属性和方法:
class OuterClass {
int x = 10;
class InnerClass {
public int myInnerMethod() {
return x;
}
}
}
public class MyMainClass {
public static void main(String[] args) {
OuterClass myOuter = new OuterClass();
OuterClass.InnerClass myInner = myOuter.new InnerClass();
System.out.println(myInner.myInnerMethod());
}
}
// 输出 10
二、Java大数BigInteger、BigDecimal
如果基本的整数和浮点数精度不够用,可以使用java.math包中的BigInteger、BigDecimal类处理包含任意长度的数字序列的数值。
1、BigInteger实现任意精度的整数运算
大数的创建
//valueOf()方法将普通的数值转换为大数
BigInteger a=BigInteger.valueOf(100);
//使用一个带字符串参数的构造器
BigInteger b=new BigInteger("1332433344333");
//内置常量ZERO、ONE这些
BigInteger c=BigInteger.ZERO;
大数的运算
Scanner in=new Scanner(System.in);
String s1=in.nextLine();
String s2=in.nextLine();
BigInteger a=new BigInteger(s1);
BigInteger b=new BigInteger(s2);
//加法add()
BigInteger c=a.add(b);
System.out.println(c);
//乘法multiply()
BigInteger d=a.multiply(b);
System.out.println(d);
//减法subtract()
BigInteger e=a.subtract(b);
System.out.println(e);
//除法divide()
BigInteger f=a.divide(b);
System.out.println(f);
//取余数mod()
BigInteger g=a.mod(b);
System.out.println(g);
其他方法
Scanner in=new Scanner(System.in);
String s1=in.nextLine();
String s2=in.nextLine();
BigInteger a=new BigInteger(s1);
BigInteger b=new BigInteger(s2);
//开平方根
//BigInteger c=a.sqrt();//java 9才有
//比较两个大数的大小
// a<b返回负数,a>b返回正数,a==b返回0
int num=a.compareTo(b);
String flag= num>=0 ? (num>0 ? "a大":"相等"):"b大";
System.out.println(flag);
2、BIgDecimal 实现任意精度的浮点数运算
其他方法与BIgInteger类似
Scanner in=new Scanner(System.in);
String s1=in.nextLine();
String s2=in.nextLine();
BigDecimal a=new BigDecimal(s1);
BigDecimal b=new BigDecimal(s2);
//除法,并指定舍入方式
BigDecimal c=a.divide(b,BigDecimal.ROUND_HALF_UP);//四舍五入
三、Java中常量、枚举类型
1、常量
特点:
- 在程序运行过程中一直不会改变,用关键字final修饰,也被称为“final变量”;
- 在整个程序中只能被赋值一次,赋值后便不可修改,为所有对象共享;
- 常量名一般使用全大写;
声明常量的标准语法:
final 数据类型 常量名=值;
如果要使某个常量在一个类的多个方法中都能够使用,可以声明为类常量,使用 static final 修饰
public class Main
{
public static final double PI=3.14;
public static void main(String[] args)
{
System.out.println(PI*2*2);
}
}
当定义的final变量属于类常量时,必须在定义的时候就赋值,否则会出错。
public class Main
{
static final double PI=3.14;//必须在定义时就赋值
public static void main(String[] args)
{
final double p;//可以分开
p=2.2;
System.out.println(PI*p*2);
}
}
2、枚举类型
变量的取值只在一个有限的集合内,枚举类型包括有限个命名的值。
例如,杯子有小中大三种型号
public class Main
{
public enum Size{SMALL,MEDIUM,LARGE};
public static void main(String[] args)
{
Size cupSize=Size.SMALL;
System.out.println(cupSize);
}
}
SMALL
比较两个枚举类型的值时,可以直接使用==。
枚举类的定义
public enum Size
{
SMALL("S"),MEDIUM("M"),LARGE("L");
private String cupSize;
//构造器总是私有的,所以private可以忽略不写
Size(String cupSize)
{
this.cupSize=cupSize;
}
public String getCupSize()
{
return cupSize;
}
}
枚举类型中的常用方法
综合应用:
import java.util.*;
public class Main
{
public enum Size
{
SMALL("S"),MEDIUM("M"),LARGE("L");
private String cupSize;
//构造器总是私有的,所以private可以忽略不写
Size(String cupSize)
{
this.cupSize=cupSize;
}
public String getCupSize()
{
return cupSize;
}
}
public static void main(String[] args)
{
Scanner in=new Scanner(System.in);
String input=in.next().toUpperCase();
Size size=Enum.valueOf(Size.class,input);//将普通字符串转换为枚举实例
System.out.println("size="+size);
System.out.println("cupSize="+size.getCupSize());
if(size==Size.MEDIUM)
{
System.out.println("YES");
}
}
}
medium
size=MEDIUM
cupSize=M
YES
四、Java使用接口
1、定义接口
接口中的方法是抽象的、公有的,一个类可以实现多个接口。
Java 8 新增:引入默认方法,静态方法,用default关键字来定义
Java 9 新增:私有方法和私有静态方法,用private修饰,私有方法必须包含方法体,必须是具体方法,且私有方法只能在该接口内使用或访问。
2、引用接口
关键字:implements
定义接口
package 基础语法;
public interface JieOne {
int add(int a,int b);
}
引用接口
package 基础语法;
class SiZeYunSuan implements JieOne,JieTwo,JieThree,JieFour{
public int add(int a,int b) {
return a+b;
}
public int sub(int a,int b) {
return a-b;
}
@Override
public int umul(int a, int b) {
// TODO 自动生成的方法存根
return a/b;
}
@Override
public int mul(int a, int b) {
// TODO 自动生成的方法存根
return a*b;
}
}
public class UseInterface {
public static void main(String[] args) {
SiZeYunSuan t=new SiZeYunSuan();
System.out.println("a+b="+t.add(2, 5));
System.out.println("a-b="+t.sub(2, 5));
System.out.println("a*b="+t.mul(2, 5));
System.out.println("a/b="+t.umul(2, 5));
}
}
在接口的实现过程中规定:
能为所有的接口提供实现的功能; 能遵循重写的所有规则; 能保持相同的返回数据类型。 接口完全支持多继承,可以有多个直接父接口,用英文逗号隔开。
五、Java方法的重写和重载
1、重写
建立在继承关系上,在子类中重新编写来自父类的方法来满足需求。
规则:
重写方法不能比被重写方法限制更严格的访问级别,即访问权限可以扩大不能缩小; final修饰的方法和静态方法都不能重写;
返回类型和参数列表保持相同; 抽象方法必须在具体类中重写;
无论被重写方法是否抛出异常,重写方法都可以抛出任何非强制异常;但重写方法不能抛出新的强制性异常,或则比被重写方法声明的范围更广的强制性异常。反之则可以。
2、重载overload
同一类中可以有两个或多个方法具有相同的方法名,但是要保证它们的参数不同,
方法重载中参数列表不同的含义是:参数的个数不同或者是参数类型不同。另外,返回类型不能用来区分方法重载
package 基础语法;
public class Chongzai {
int max(int a,int b) {
System.out.println("int max:");
return a>b?a:b;
}
int max(short a,short b) {
System.out.println("int max(short):");
return a>b?a:b;
}
public static void main(String args[]) {
Chongzai tChongzai=new Chongzai();
tChongzai.max(3, 4);
short a=3;//先定义为short,否则默认int
short b=4;
tChongzai.max(a, b);
}
}
六、序列化
1、序列化与反序列化
package com.java.main;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class TestObject
{
public static void main(String[] args)
{
ObjectStream objectStream = new ObjectStream();
objectStream.testObjectOutputStream();
objectStream.testObjectInputStream();
}
}
class ObjectStream
{
/*
* 序列化过程:将内存中的Java对象保存到磁盘中或者通过网络传输出去
*/
public void testObjectOutputStream()
{
ObjectOutputStream oos = null;
try
{
oos = new ObjectOutputStream(new FileOutputStream("D:\\CODE\\codeeclipse\\Java基础\\src\\com\\java\\main\\data.txt"));
oos.writeObject(new String("你好Java"));
oos.flush(); // 刷新一下
}catch(IOException e)
{
e.printStackTrace();
}finally
{
if(oos != null)
{
try
{
oos.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
}
/*
* 反序列化过程:将磁盘中的对象还原成内存中的Java对象
*
*/
public void testObjectInputStream()
{
ObjectInputStream ois = null;
try
{
ois = new ObjectInputStream(new FileInputStream("D:\\CODE\\codeeclipse\\Java基础\\src\\com\\java\\main\\data.txt"));
Object obj = ois.readObject();
String string = (String)obj;
System.out.println(string);
}catch(IOException e)
{
e.printStackTrace();
} catch (ClassNotFoundException e)
{
e.printStackTrace();
}finally
{
if(ois != null)
{
try
{
ois.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
}
}
自定义的类的对象如果需要序列化与反序列化,就需要实现Serializable接口,而且该类要提供一个全局常量serialVersionUID(用来标识序列化版本)
自定义类的所有属性都必须可序列化
class Person implements Serializable
{
/**
* 需要提供一个全局常量 serialVersionUID
*/
private static final long serialVersionUID = 1L;
private String name;
private int age;
public Person(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 "Person [name=" + name + ", age=" + age + "]";
}
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class TestObject
{
public static void main(String[] args)
{
ObjectStream objectStream = new ObjectStream();
objectStream.testObjectOutputStream();
objectStream.testObjectInputStream();
}
}
class ObjectStream
{
/*
* 序列化过程:将内存中的Java对象保存到磁盘中或者通过网络传输出去
*/
public void testObjectOutputStream()
{
ObjectOutputStream oos = null;
try
{
oos = new ObjectOutputStream(new FileOutputStream("D:\\CODE\\codeeclipse\\Java基础\\src\\com\\java\\main\\data.txt"));
oos.writeObject(new Person("张三", 21)); // 序列化自定义的类对象person
oos.flush(); // 刷新一下
}catch(IOException e)
{
e.printStackTrace();
}finally
{
if(oos != null)
{
try
{
oos.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
}
/*
* 反序列化过程:将磁盘中的对象还原成内存中的Java对象
*
*/
public void testObjectInputStream()
{
ObjectInputStream ois = null;
try
{
ois = new ObjectInputStream(new FileInputStream("D:\\CODE\\codeeclipse\\Java基础\\src\\com\\java\\main\\data.txt"));
Object obj = ois.readObject();
Person person = (Person)obj;
System.out.println(person);
}catch(IOException e)
{
e.printStackTrace();
} catch (ClassNotFoundException e)
{
e.printStackTrace();
}finally
{
if(ois != null)
{
try
{
ois.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
}
}
2、RandomAccessFile
既可以实现输入,也可以实现输出
package com.java.main;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
public class TestRandom
{
public static void main(String[] args)
{
RandomAccessFile raf1 = null;
RandomAccessFile raf2 = null;
try
{
raf1 = new RandomAccessFile(new File("C:\\Users\\zzps\\Pictures\\Saved Pictures\\手写签名照.jpg"), "r");
raf2 = new RandomAccessFile(new File("C:\\Users\\zzps\\Pictures\\Saved Pictures\\手写签名照1.jpg"), "rw");
byte[] bBuffer = new byte[1024];
int len;
while((len = raf1.read(bBuffer)) != -1)
{
raf2.write(bBuffer, 0, len);
}
}catch(IOException e)
{
e.printStackTrace();
}finally
{
if(raf1 != null)
{
try
{
raf1.close();
} catch (IOException e)
{
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
if(raf2 != null)
{
try
{
raf2.close();
} catch (IOException e)
{
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
}