呵呵,问大家一个问题:final变量在赋值以后能否修改?你的答案是不能,错!可以,看里面的程序。

cherami 2002-01-31 08:58:10
import java.io.*;


public class STDIORedirect
{
public static void main (String args[])
{
// Save the current standard input, output, and error streams
// for later restoration.
InputStream origIn = System.in;
PrintStream origOut = System.out;
PrintStream origErr = System.err;

// Create a new input stream from a file.
InputStream stdin = null;
try
{
stdin = new FileInputStream ("Redirect.in");
}
catch (Exception e)
{
// Sigh. Couldn't open the file.
System.out.println ("Redirect: Unable to open input file!");
System.exit (1);
}

// Create a new output stream for the standard output.
PrintStream stdout = null;
try
{
stdout = new PrintStream (
new FileOutputStream ("Redirect.out"));
}
catch (Exception e)
{
// Sigh. Couldn't open the file.
System.out.println ("Redirect: Unable to open output file!");
System.exit (1);
}

// Create new output stream for the standard error output.
PrintStream stderr = null;
try
{
stderr = new PrintStream (
new FileOutputStream ("Redirect.err"));
}
catch (Exception e)
{
// Sigh. Couldn't open the file.
System.out.println ("Redirect: Unable to open error file!");
System.exit (1);
}

// Print stuff to the original output and error streams.
// On most systems all of this will end up on your console when you
// run this application.
origOut.println ("\nRedirect: Round #1");
System.out.println ("Test output via 'System.out'.");
origOut.println ("Test output via 'origOut' reference.");
System.err.println ("Test output via 'System.err'.");
origErr.println ("Test output via 'origErr' reference.");

// Set the System out and err streams to use our replacements.
System.setIn ( stdin );
System.setOut ( stdout );
System.setErr ( stderr );

// Print stuff to the original output and error streams.
// The stuff printed through the 'origOut' and 'origErr' references
// should go to the console on most systems while the messages
// printed through the 'System.out' and 'System.err' will end up in
// the files we created for them.
origOut.println ("\nRedirect: Round #2");
System.out.println ("Test output via 'System.out'.");
origOut.println ("Test output via 'origOut' reference.");
System.err.println ("Test output via 'System.err'.");
origErr.println ("Test output via 'origErr' reference.");

// Read some input and dump it to the console.
origOut.println ("\nRedirect: Round #3");
int inChar = 0;
while (-1 != inChar)
{
try
{
inChar = System.in.read();
}
catch (Exception e)
{
// Clean up the output and bail.
origOut.print ("\n");
break;
}
origOut.write (inChar);
}

// Close the streams.
try
{
stdin.close ();
stdout.close ();
stderr.close ();
}
catch (Exception e)
{
origOut.println ("Redirect: Unable to close files!");
System.exit (1);
}

System.exit (0);
}
}
查查JDK的API可以知道,在JDK1.0中,System.in,System.out和System.err是public static变量,但是1.1以后就是public static final了,但是System类提供了setIn,setOut和setErr对这三个final变量进行重新赋值,这个就打破了final变量不能被重新赋值的神话,但是SUN到底如何实现的还不得而知,我正在查找有关资料,有知情的朋友说句话。呵呵,先谢了!
...全文
448 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
cherami 2002-02-02
  • 打赏
  • 举报
回复
to waterdragonfly(水蜻蜓):
使用数组当然可以修改数组元素的值,但问题是这几个变量都不是在数组中啊!
cherami 2002-02-02
  • 打赏
  • 举报
回复
Netix(雷霆)的意思是对的,使用本机方法可以修改final变量,但是从上面给出的那段话里面可以知道JVM实际上是允许对final变量进行修改的,只是编译器屏蔽了源代码中的这种方法,至于SUN是通过本机方法实现的还是通过修改编译后的class实现的就不清楚了。
cherami 2002-02-02
  • 打赏
  • 举报
回复
to sharetop(天生不笨):
你在好好看看吧。肯定是final:
Field Detail
in
public static final InputStream inThe "standard" input stream. This stream is already open and ready to supply input data. Typically this stream corresponds to keyboard input or another input source specified by the host environment or user.
以上是我摘自JDK1.3的API文档。


以下是我找到的另一篇文章的内容节选:
You can't close over anything but final variables in an inner class! Their rationale is that it might be ``confusing.'' Of course you can get the effect you want by manually wrapping your variables inside of one-element arrays. The very first time I tried using inner classes, I got bitten by this -- that is, I naively attempted to modify a closed-over variable and the compiler complained at me, so I in fact did the one-element array thing. The only other time I've used inner classes, again, I needed the same functionality; I started writing it the obvious way and let out a huge sigh of frustration when, half way through, I realized what I had done and manually walked back through the code turning my
Object foo = <whatever>;

into
final Object[] foo = { <whatever> };

and all the occurence of foo into foo[0]. Arrrgh!

The access model with respect to the mutability (or read-only-ness) of objects blows. Here's an example:
System.in, out and err (the stdio streams) are all final variables. They didn't used to be, but some clever applet-writer realized that you could change them and start intercepting all output and do all sorts of nasty stuff. So, the whip-smart folks at Sun went and made them final. But hey! Sometimes it's okay to change them! So, they also added System.setIn, setOut, and setErr methods to change them!

``Change a final variable?!'' I hear you cry. Yep. They sneak in through native code and change finals now. You might think it'd give 'em pause to think and realize that other people might also want to have public read-only yet privately writable variables, but no.

Oh, but it gets even better: it turns out they didn't really have to sneak in through native code anyway, at least as far as the JVM is concerned, since the JVM treats final variables as always writable to the class they're defined in! There's no special case for constructors: they're just always writable. The javac compiler, on the other hand, pretends that they're only assignable once, either in static init code for static finals or once per constructor for instance variables. It also will optimize access to finals, despite the fact that it's actually unsafe to do so.



Netix 2002-02-01
  • 打赏
  • 举报
回复
System类的setIn(in)方法:
{
checkIO();
setIn0(in);
}
CheckIO()方法:
private static void checkIO()
{
if (security != null)
security.checkPermission(new RuntimePermission("setIO"));
}
setIn0(in)方法:
private static native void setIn0(InputStream in);
改变final成员并非Java实现,而是本地实现,这就很难说了。不知道哪位高手可以找到native方法的源代码,大家一起讨论讨论。
waterdragonfly 2002-02-01
  • 打赏
  • 举报
回复
class A {
final int[] a=new int[1];

public A() {
a[0]=100;
System.out.println("a[0]="+a[0]);
a[0]=101;
System.out.println("a[0]="+a[0]);
}
}
用数组不就行了?
gdsean 2002-02-01
  • 打赏
  • 举报
回复
那段程序跟final有什么关系??
skyyoung 2002-02-01
  • 打赏
  • 举报
回复
给出原代码。
sharetop 2002-02-01
  • 打赏
  • 举报
回复

我看了API,jdk1.3的,in,out,err都是public static呀?没说是final的????
你在哪看到它们从1.1开始都是final了???

23,404

社区成员

发帖
与我相关
我的任务
社区描述
Java 非技术区
社区管理员
  • 非技术区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧