面向对象的历史。
类(class)是对象(object)的设计图纸,定义了对象的数据结构和操作。
局部变量:method()里的 int n = 0;
对象成员变量:double v1 = 100;
类成员变量:static int V = 100;
public class circle()
{
private double radius;
public circle(double radius)
{
this.setradius(radius);
}
public double getradius()
{
return radius;
}
public void setradius()
{
this.radius = radius;
}
}
public class Test{
public static void main(String[] args)
{
Scanner input = new Scanner(System.in);
System.out.print("输入信息:");
String s = input.next();
System.out.println("打印信息:"+ s);
}
System.in为标准输入流,需要联合Scanner类一起使用。
Scanner sc = new Scanner(System.in);
Scanner类提供了多种读取的方式:nextInt读取下一个整数,nextLine读取下一行等。
注意:因为此种输入方式是可见的,所以Scanner类不适用于从控制台读取密码。Java6特别引入了Console类来实现这个目的。
import java.util.Scanner; // 需要导入 util 包
Scanner input = new Scanner(System.in);
String str1 = input.next();
String str2 = input.nextLine(); // 获取字符串
int number1 = input.nextInt(); // 获取整数
float number2 = input.nextFloat(); // 获取浮点数据
//循环输入
while (input.hasNextInt()) {
int tmp = input.nextInt();
}
System.out.println(tmp); // 与println效果相同
input.close(); // 掉用完成关闭方法
next()
一定要读取到有效字符后才可以结束输入。
对输入有效字符之前遇到的空白,next()方法会自动将其去掉。
只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
next()不能得到带有空格的字符串。
nextLine()
以Enter为结束符,也就是说nextLine()方法返回的是输入回车之前的所有字符。
可以获取到空白。
1、标准输出流
最常用的就是标准输出流
System.out.println();
2、格式化输出
除此之外,还可以格式化输出。Java5沿用了C语言函数库中的printf方法。
System.out.printf("%8.2f",x);
想要读取一个文件,需要构造一个Scanner对象
Scanner in = new Scanner(Path.of("myfile.txt"),StandardCharsets.UTF_8);
如果想写入一个文件,则需要构造一个PrintWriter对象
PrintWriter out = new PrintWriter("myfile.txt",StandardCharsets.UTF_8);
对于这种相对文件名的方式指定的,其实际位置位于Java虚拟机启动目录的位置。
需要注意的是,访问不存在的文件或写入的文件名不合规则会抛出异常。
for-each循环是Java相比C语言中的for循环拓展而来的一种新的遍历数组的循环方式。for-each循环通过对数组内元素类型相同的变量进行遍历,直接数组内从下标为0的位置至最后一个位置的元素的元素值。
for-each循环基本语句
for ( 变量类型 变量名 : 数组名 ) {
需要执行的循环语句;
}
示例
int [] a = new int [10];
//for循环遍历
for ( int i=0 ; i<10 ; i++ )
a[i];
//for-each循环遍历
for ( int k : a);
实例
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int [] data = {56, 75, 68, 45, 24, 245, 2, 5, 22, 27, 5};
int x = 0;
Scanner in = new Scanner ( System.in );
x = in.nextInt();
boolean found = false;
for ( int k : data ) {
if ( k==x ) {
found = true;
break;
}
}
if ( found )
System.out.println("找到了");
else
System.out.println("没找到");
in.close();
}
}
使用interface的方法,抽象类中的抽象函数实质上也是属于接口范畴。
泛型编程是JAVA 5加入的特征,实现代码中类型参数化的功能。
Java泛型的应用可以提高代码的复用性,同时泛型提供了类型检查,减少了数据的类型转换,同时保证了类型的安全。下面来看一下,泛型如何保证了类型的安全:
List list = new ArrayList();
list.add("abc");
list.add(new Integer(1)); //可以通过编译
for (Object object : list) {
System.out.println((String)object);//抛出ClassCastException异常
}
上面的代码会在运行时抛出ClassCastException,因为它尝试将一个Integer转换为String。接着,来看一下从java5开始,Collection的用法:
List<String> list = new ArrayList<>();
list.add("abc");
//list.add(new Integer(1)); //编译错误
for (String string : list) {
System.out.println(string);//无需任何强制类型转换
}
注意到,List的创建增加了类型参数String,因此只能向list添加String类型对象,添加其他对象会抛出编译异常;同样可以注意到,foreach循环不需要再添加任何强制类型转换,也就移除了运行时的ClassCastException异常。
既然是学泛型,自然就要知道如何去使用泛型定义自己的类和接口。同时为了加深理解泛型的作用,我们先定义一个不适用泛型的类:
public class Gen {
private Object obj;
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
public static void main(String[] args) {
Gen gen = new Gen();
gen.setObj("abc");
String str = (String) gen.getObj();//类型转换,可能会引起运行时ClassCastException
}
}
原始类的定义,容易引发ClassCastException,因为在使用的时候我们无法知道具体的类型到底是什么。现在来看一下泛型类来重新定义Gen — 使用<>指定泛型参数,如下:
public class Gen<T> {
T obj;
public T getObj() {
return obj;
}
public void setObj(T obj) {
this.obj = obj;
}
public static void main(String[] args) {
Gen<String> gen = new Gen<>();
gen.setObj("abc");
// gen.setObj(10); //无法通过编译
String str = gen.getObj(); //无需类型转换
//-----------------------------
Gen gen2 = new Gen();//raw type原始类型
gen2.setObj("abc");
gen2.setObj(10); //可以通过编译,自动装箱将10转化为Integer对象
Integer num = (Integer) gen2.getObj();//使用了强制类型转换
}
}
main()方法里是使用泛型类型Gen,便不再需要强制类型转换,也就移除了运行时的ClassCastException。同时为了区别,在此也定义了一个没有使用泛型类型的gen2,这时,编译器会弹出一个警告“Gen is a raw type,References to generic type Gen should be parameterized”。当我们不提供泛型类型时,会默认使用Object会代替,也是因此这样,gen2可以设置String和Integer类型,不过,我们应尽量去避免这种这种情况的出现,如此,便又需要用到强制类型转换,也伴随着运行时的ClassCastException异常。
可以使用@SuppressWarnings(“rawtypes”)来忽略编译器弹出警告。
接口的泛型应用和类的泛型应用非常类似:
public interface List <E> {
void add(E x);
Iterator<E> iterator();
}
public interface Iterator<E> {
E next();
boolean hasNext();
}
另外,在定义泛型类和泛型接口的时候,我们也可以定义多个泛型化参数。例如Java中的Map
在使用泛型类的时候,我们就需要将泛型参数具体化,例如:
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("ABC");
list.add(123);//报错!由于泛型已经具体化成String类型,就不能使用整数类型了
}
需要注意的是,当我们将泛型参数具体化成String类型之后,原本ArrayList中的add(E e)方法的参数类型就会变成String类型,这时候在调用add()方法的时候,就只能传入String类型的参数了。
另外,在Java中明确的规定了泛型参数在具体化的时候只能使用引用类型,所以是有的泛型参数必须使用Object类型及其子类类型,如果使用基本类型,就会出错:
//这里不能使用基本类型来具体化泛型参数
ArrayList<int> list = new ArrayList<>();
泛型类的继承和泛型接口的实现
我们在实现泛型接口的时候,也必须要定义泛型类去实现泛型接口。例如:
public class ArrayList<E> implements List<E>{
}
为了更好地去理解泛型,我们也需要去理解java泛型的命名规范。各种常用泛型参数的意义如下:
E — Element,常用在java Collection里,如:List,Iterator,Set
K,V — Key,Value,代表Map的键值对
N — Number,数字
T — Type,类型,如String,Integer等等
S,U,V etc. - 2nd, 3rd, 4th 类型,和T的用法一样。
有些时候,我们可能并不希望将整个类都泛型化。这个时候我们就可以只在某个方法上定义泛型,构造方法也是一样。例如:
public class GenMethod {
public static <T> void fromArrayToCollection(T[] a,Collection<T> c){
for (T t : a) {
c.add(t);
}
}
public static void main(String[] args) {
Object[] oa = new Object[100];
Collection<Object> co = new ArrayList<>();
GenMethod.<Object>fromArrayToCollection(oa, co);
}
}
定义方法所用的泛型参数需要在修饰符之后添加,如上面的,public static ,如果有多个泛型参数,可如此定义
如果两个类之间有继承被被继承的关系,那么我们就可以将一个类的对象赋值类另外一个类的对象,比如:
String str = new String();
Object obj = new Object();
obj = str;
这种关系同样适用于泛型。比如我们将泛型参数设置为Number,那么在随后的调用中,就只需要传入一个Number类型或者是Number的子类类型的对象就行了,比如Integer,Float,Double都可以:
ArrayList<Number> list = new ArrayList<>();
list.add(new Integer(1));
list.add(new Float(1.0));
list.add(new Double(1.0));
但是有一种情况是我们需要特别注意的,比如我们定义一个如下的方法:
public void someMethod(ArrayList<Number> n) {
}
这个方法能接受什么样类型的参数类?
ArrayList?
ArrayList?
ArrayList?
显然ArrayList。
原因是:虽然Integer和Double是Number类型的子类,但是ArrayList和ArrayList类型并不是ArrayList类型的子类。
在泛型里也存在子类型,前提是其泛型参数的限制并没有发生改变,或者说泛型没有改变。其实就是从原来的类或接口来判断泛型的子类型。
比如ArrayLIst implements List,而List extends Collection,那么ArrayList就是List的子类型,而List又是Collection的子类型。
有时候,你会希望泛型类型只能是某一部分类型,比如在操作数据的时候,你希望是Number或其子类类型。这个通常的做法就是给泛型参数添加一个参数。其定义的形式为:
<T extends ParentType>
这个定义表示T应该是Numner的子类型,T和Parant可以是类,也可以是接口,注意此处的extends表示的是ParentType的子类型,和继承是有区别的。
public class Box<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
public <U extends Number> void inspect(U u) {
System.out.println("T: " + t.getClass().getName());
System.out.println("U: " + u.getClass().getName());
}
public static void main(String[] args) {
Box<String> integerBox = new Box<>();
integerBox.set("abc"); //能通过编译,因为T指定为String类型
// integerBox.inspect("abc");//不能通过编译,因为U必须是Number类型或其子类
integerBox.inspect(new Integer(10));
}
}
Java为每种基本数据类型都提供了对应的包装器类型。
在Java SE5之前,如果要生成一个数值为10的Integer对象,必须这样进行:
Integer i = new Integer(10);
而在从Java SE5开始就提供了自动装箱的特性,如果要生成一个数值为10的Integer对象,只需要这样就可以了:
Integer i = 10;
这个过程中会自动根据数值创建对应的 Integer对象,这就是装箱。
那什么是拆箱呢?顾名思义,跟装箱对应,就是自动将包装器类型转换为基本数据类型:
Integer i = 10; //装箱
int n = i; //拆箱
简单一点说,装箱就是 自动将基本数据类型转换为包装器类型;拆箱就是 自动将包装器类型转换为基本数据类型。
1、实体中数值类型一般定义为包装类型
2、接受参数推荐定义为包装类型
目的:避免null导致程序异常。
public class Main {
public static void main(String[] args) {
Integer i = 10;
int n = i;
}
}
装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的 xxxValue方法实现的。(xxx代表对应的基本数据类型)。
集合元素不支持原始数据类型:ArrayList< int >,需要修改为ArrayList< Integer >。
包装类为final类型,表示该类不能被继承(扩展)。
被包装的值value为final类型,表示初始化后不能被修改,这种类也称为immutable.
参考博文:https://blog.csdn.net/zhou520yue520/article/details/80952404