System.out.println()的正确理解

System.out.println();

初学的时候对这个语句很是困惑,查了很多资料多半都是说的模棱两可,先入为主。但是它到底要怎么去理解呢?

由字面意思我们很容易得出pintln()是一个方法,被System.out的调用,用于向控制台打印输出,但是这里系统是什么?出去又是什么呢?

  • 解释1

系统类里有大量的本地方法,是调用本地代码的,这些代码很可能是由虚拟机来调用的。 

系统类的开头有一段:

Java代码

静态的 { 

registerNatives(); 

} 

 

这段代码会在虚拟机启动的时候就执行,它在虚拟机里注册系统需要使用的一些本地代码 

比如:

Java代码

privatestaticnative属性initProperties(属性道具); 

privatestaticnativevoid setOut0(PrintStream out); 

 

在窗户下的话,它就告诉虚拟机到哪个DLL文件里去找相应的实现

Java代码

/ ** 

*存在以下两种方法,因为in,out和err必须是 

*初始化为null。但是,不允许编译器 

*内联访问它们,因为它们后来被设置为更合理的值 

*通过initializeSystemClass()。 

* / privatestatic InputStream nullInputStream()抛出NullPointerException { 

if(currentTimeMillis()> 0) 

returnnull; 

thrownew NullPointerException(); 

}

 

也就说in,out,和err初始化为null,然后会在后来由initializeSystemClass()方法类初始化成有意义的值

Java代码

/ ** 

*初始化系统类。线程初始化后调用。 

* / privatestaticvoid initializeSystemClass(){ 

props = new Properties(); 

initProperties(道具); 

sun.misc.Version.init(); 

FileInputStream fdIn = new FileInputStream(FileDescriptor.in ); 

FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out); 

FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err); 

setIn0(new BufferedInputStream(fdIn));  

setOut0(new PrintStream(new BufferedOutputStream(fdOut,128),true));  

setErr0(new PrintStream(new BufferedOutputStream(fdErr,128),true)); !!! //现在世界已经足够我们可以冒险了 

//初始化日志记录配置。尝试{ 

。java.util.logging.LogManager.getLogManager()readConfiguration(); 

} catch(Exception ex){ 

// System.err.println(“无法读取日志记录配置:”); 

// ex.printStackTrace(); } 

//现在加载zip库以保留java.util.zip.ZipFile 

//稍后尝试使用自己加载此库 的LoadLibrary( “拉链”); 

//在初始化期间调用的子系统可以调用 

// sun.misc.VM.isBooted()以避免做那些应该做的事情 

//等到应用程序类加载器设置完毕。sun.misc.VM.booted(); 

}

 

输入,输出,犯错就是在以上方法以下三条语句里初始化的。

Java代码

 

setIn0(new BufferedInputStream(fdIn));  

setOut0(new PrintStream(new BufferedOutputStream(fdOut,128),true));  

setErr0(new PrintStream(new BufferedOutputStream(fdErr,128),true));

 

Java代码

privatestaticnativevoid setIn0(InputStream in); 

 

这是个本地函数,是前面registerNatives()的时候注册了的。这个函数应该是把实际连接到输入输出设备的句柄传给虚拟机并赋值给IN,OUT,ERR

  • 解释2

 

同学你看错了......

 

源码是public final static PrintStream out = nullPrintStream();

然后

private static PrintStream nullPrintStream()抛出NullPointerException {

if(currentTimeMillis()> 0){

return null;

}

抛出新的NullPointerException();

}

 

然后这方法的注释:

/ **

*存在以下两种方法,因为in,out和err必须是

*初始化为null。但是,不允许编译器

*内联访问它们,因为它们后来被设置为更合理的值

*通过initializeSystemClass()。

* /

 

  • 解释3

你没有看全源代码,当导入系统类的时候,已经走了静代代码块完成了out initial beginningization

看源代码System.java

//首次使用时初始化System中的所有插槽。

静态的 {

long hiresFrequency = hiresFrequencyImpl();

if(hiresFrequency == 1000000000L){

nanoType = NANO_RETURN;

nanoAdjust = 0;

nanoIntAdjust = 0;

} else if(hiresFrequency <1000000000L){

nanoAdjust =(double)1000000000L / hiresFrequency;

if(Math.floor(nanoAdjust)== nanoAdjust){

nanoType = NANO_INT_MULTIPLY;

nanoIntAdjust =(long)nanoAdjust;

} else {

nanoType = NANO_MULTIPLY;

nanoIntAdjust = 0;

}

} else {

nanoAdjust = hiresFrequency /(double)1000000000L;

if(Math.floor(nanoAdjust)== nanoAdjust){

nanoType = NANO_DIVIDE;

nanoIntAdjust =(long)nanoAdjust;

} else {

nanoType = NANO_DIVIDE;

nanoIntAdjust = 0;

}

}

//从VM信息中填写属性。

ensureProperties();

//设置标准输入,输出和错误。

//检查默认编码

StringCoding.encode(new char [1],0,1);

err = com.ibm.jvm.io.ConsolePrintStream.localize(new BufferedOutputStream(new FileOutputStream(FileDescriptor.err)),true);

/// **********初始化出在这里**********

out = com.ibm.jvm.io.ConsolePrintStream.localize(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)),true);

in = null;

com.ibm.misc.SystemIntialization.firstChanceHook();

}

解释4

你看的很仔细说的也很对由于java的是支持多线程的,所以标准的输入输出是共享,因此它们必须受到特别的处理,在系统初始化完成之前,线程严禁使用这几个特殊对象;又因为这些对象都是静态的,因此java的的类加载机制会在系统类加载的时候就会初始化,这就造成了一对矛盾;为解决这对矛盾,系统在加载是将它们初始化为空值,等加在完成后,通过天然方法在对它们进行赋值:看看这个:公共最终静态中= nullInputStream()的InputStream;私有静态的InputStream nullInputStream()抛出的NullPointerException {如果(的currentTimeMillis()> 0){返回NULL; 抛出新的NullPointerException(); }在线程初始化完成后,系统会调用方法initializeSystemClass设置这几个特殊对象的值:的FileInputStream fdIn =新的FileInputStream(FileDescriptor.in); FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out); FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err); setIn0(new BufferedInputStream(fdIn)); setOut0(new PrintStream(new BufferedOutputStream(fdOut,128),true)); setErr0(new PrintStream(new BufferedOutputStream(fdErr,128),true)); [

 

解释5

一般解释

println()方法用于打印控件并将其传递给新行。它是PrintStream类的一种方法。对象调用方法。因此out是PrintStream类的对象。System是一个类,它指定要生成输出的硬件(此处)。因此,输出在控制台产生。

 

在System类中声明的外观如下所示:public static final PrintStreamout,Prinstream类内部是一个具有如下方法签名的println()声明的声明:public void println()。 

 

它可以理解像... 

导入 java.io *; 

类系统 { 

public static PrintStream out = new PrintStream(); 

... 

} 

 

class PrintStream { 

public void println(String s){...} 

public void println(int i){...} 

public void println(long l){...} 

... 

} 

 

 

System.out的PrintStream的该类的一个实例的println 是一个实例方法的PrintStream (实际上的println 该类中有多个方法)。

你可以看到如何系统类上的声明

public final static PrintStream out = null;

 

的System.out.println(); 实现 - 堆栈溢出

在System.out.println中,

  • 系统是最后一堂课。
  • out是系统内PrintStream类的对象。
  • println()是PrintStream的一种方法

所以要打印一些我们需要调用println的东西,它位于PrintStream类中,其对象在System class.Hence System.out.println();

有关更多信息,请参阅以下链接 

 

 

 

 

 

### 关于生肖的Java代码修正与理解 在Java中,用于输出生肖的代码通常涉及根据年份计算对应的生肖。以下是一个典型的例子,帮助你理解或修正相关代码: ```java public class ChineseZodiac { public static void main(String[] args) { int year = 2023; // 示例年份 String zodiac = getChineseZodiac(year); System.out.println("Year " + year + " corresponds to the zodiac: " + zodiac); } public static String getChineseZodiac(int year) { String[] zodiacs = { "Monkey", "Rooster", "Dog", "Pig", "Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Sheep" }; return zodiacs[(year - 1900) % 12]; // 1900是基准年,可以根据需要调整 } } ``` #### 代码解析 1. **数组定义**:定义一个包含12个生肖名称的字符串数组`zodiacs`[^5]。 2. **计算公式**:通过`(year - 1900) % 12`计算年份对应的生肖索引。这里选择1900作为基准年是因为1900年的生肖是“Monkey”[^5]。 3. **返回结果**:根据计算得到的索引,从数组中取出对应的生肖名称并返回。 如果代码运行时出现错误,可能的原因包括: - 年份输入不正确(如负数或非整数)。 - 数组索引超出范围(可能是由于基准年设置不当)。 #### 常见问题及解决方法 - **问题1**:如果输入的年份小于基准年(如1900),会导致错误的计算结果。 - **解决方法**:确保输入的年份大于等于基准年,或者调整基准年以适应更早的年份。 - **问题2**:如果数组定义错误或缺失某些生肖名称,会导致输出不完整。 - **解决方法**:检查数组定义是否完整且顺序正确。 ### 示例修正 假设用户提供的代码中存在错误,例如未正确处理年份或数组定义不完整。以下是一个修正后的版本: ```java public class ZodiacCalculator { public static void main(String[] args) { int year = 1984; // 示例年份 String zodiac = calculateZodiac(year); System.out.println("The zodiac for year " + year + " is: " + zodiac); } public static String calculateZodiac(int year) { if (year < 0) { return "Invalid year"; // 处理负数年份 } String[] zodiacs = { "Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Sheep", "Monkey", "Rooster", "Dog", "Pig" }; return zodiacs[(year - 4) % 12]; // 4对应1904年的“Rat” } } ``` #### 注意事项 - 如果用户的代码中未明确基准年,可以使用1904年(鼠年)作为参考[^6]。 - 确保数组中的生肖顺序与实际年份匹配,避免因顺序错误导致输出错误。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值